e70d7a667b
build / mod (push) Failing after 18s
Record actual save field positions, motor phases, finite typed delivery, last-known radar contacts and blast-cover policy. Include per-seed baseline measurements and distinguish native/WASM checks from pending GUI acceptance. Co-authored-by: Codex <codex@openai.com>
240 lines
24 KiB
Markdown
240 lines
24 KiB
Markdown
# Передача разработки AirDef
|
||
|
||
Это журнал фактически сделанных изменений и ограничений проверки, а не список обещанных функций.
|
||
Рабочая ветка `kimi-work`; issues не закрывать, публиковать комментарии с коммитом и проверками.
|
||
Движок — отдельный `chexit/horizon-airdef`, ветка `airdef`, подключён точным gitlink `horizon/`.
|
||
|
||
## Текущее состояние: 3 ноября 2026
|
||
|
||
Код четырёх задач интегрирован и опубликован до `6e2d661`. Движок в этой серии не менялся.
|
||
README описывает доступное поведение; `IMPLEMENTATION-STATUS.md` отделяет реализацию от приёмки.
|
||
Ни одно issue не закрыто. Участники: Codex (интеграция, #119, ревью, документация) и три
|
||
GPT-6.1 Terra (энергетика, типизированная доставка, излучение). Новые числа — только игровые.
|
||
|
||
| Issue | Опубликованные контрольные коммиты |
|
||
|---|---|
|
||
| #119 | `c96676f`: укрытия, read-only geometry, четыре проверки |
|
||
| #118 | `c775f31`, `952a10f`: доставка ТЗМ, возврат снятой ракеты ПВО, реальное движение и save/restore |
|
||
| #121 | `26b258f`, `0df225a`, `88f9405`, `9e1e0f5`, `b377a5d`, `ce76f20`: излучение, UI/save/replay, наблюдения, last-known SEAD |
|
||
| #120 | `143d9b2` → `e38ca0d`, затем `a7b8cb9`: конечное горение, coast, swept impact, диагностика, звук, исправленное ветвление фаз |
|
||
| WASM | `6e2d661`: проверка On/Off и запрета управления отсутствующим радаром, 24 шага |
|
||
|
||
Для обновления существующей установки сначала `git switch kimi-work`, затем `git pull --ff-only`,
|
||
`python3 tools/airdef.py all`, `python3 tools/airdef.py play`. `all` обновляет точный сабмодуль,
|
||
собирает игру/мод и устанавливает пакет. На Windows обычно используется `python` вместо `python3`.
|
||
|
||
## Исходная контрольная точка этой серии
|
||
|
||
Исходное состояние этой серии: `2689d93`; движок закреплён на
|
||
`86b1014a9218e68041444cbf52db02a85107c815`, уровень API 26. Рабочее дерево было чистым,
|
||
коммиты опубликованы. Текущий точный pin всегда смотреть в `git ls-files --stage horizon`,
|
||
а происхождение собранного пакета — в `airdef-mod/target/horizon-mod/build-identity.json`.
|
||
|
||
Четыре задачи были заказаны владельцем отдельно:
|
||
|
||
| Issue | Заказанный остаток |
|
||
|---|---|
|
||
| #120 | Конечная работа двигателя перехватчика, coast, энергия манёвра, согласованные эффекты |
|
||
| #118 | Типизированная доставка RM48U через ТЗМ; не создавать неподтверждённые носители |
|
||
| #121 | Переключение излучения, сохранение разрешённого внешнего целеуказания, разведка излучателей |
|
||
| #119 | Ослабление непрямого урона известным укрытием, ограниченная политика Unknown |
|
||
|
||
Исполнители работали в отдельных worktree; их проверенные коммиты перенесены в `kimi-work`.
|
||
В ветках `codex/issue-*` сохранены промежуточные версии; продолжать нужно от `kimi-work`,
|
||
где разрешены конфликты общего формата сохранений и сигнатур боевых функций.
|
||
|
||
## Что уже сделано в предыдущей серии Codex
|
||
|
||
- `airdef-core` компилирует исходники `airdef-mod/src/sim/mod.rs` через `#[path]`.
|
||
Это единый источник симуляции, но разделение домена и представления ещё не завершено (#87).
|
||
- Исправлены остаточные терминальные коллизии ответных ударов и скачок после world-query (#106/#117).
|
||
Восстановление ответов мира не даёт права телепортироваться к плановой точке.
|
||
- Доработаны запись ответных ударов, launch one-shot и live-след (#109), lifecycle показа и часы
|
||
отложенного звука (#88/#89). Полная унификация всех потребителей сцены ещё не закончена.
|
||
- Движок вынесен в отдельную репу; сборщик берётся из закреплённого форка, а не случайного PATH.
|
||
Есть build identity, настоящий WASM contract и handshake доступности дыма API26 (#102/#104).
|
||
- Обновлён upstream Horizon 0.2.97, исправления очереди/инвалидации акустики сохранены.
|
||
Измерительные fixtures, notices и лицензии добавлены; прослушивание и массовый CPU-тест ещё нужны (#96).
|
||
- Pipeline поддерживает authored overrides, manifest и экспорт итоговых габаритов в
|
||
`sim/generated_bounds.rs`. Навигация учитывает footprint. Generated output вручную не редактировать.
|
||
- Улучшены модели наземной техники; степень сходства и материалы ещё промежуточные (#115).
|
||
Галерея: `MODEL-PILOTS.md`, `VEHICLE-MODELS.md`; это не приёмка всех летательных аппаратов.
|
||
- `966b52f`: раздельные ПУ С-400/С-500, роли Radar Search/Engagement/Height/Multi.
|
||
Чужая подсказка разрешает огневому радару уточнение, но не подменяет собственное измерение.
|
||
- `966b52f`: резерв конкретной ячейки, отдельные крышки ТПК, выброс до включения двигателя.
|
||
RM48U — условный игровой профиль С-400; AA и ground rounds делят четыре физические ячейки.
|
||
Боеприпас списывается при выбросе, не при выдаче отложенного приказа; отмена не расходует его.
|
||
- Конфигурация, маска использованных ячеек и положение крышек включены в save/replay.
|
||
Smoke начинается в точке зажигания. С-500 ограничен двумя ракетами по числу ТПК;
|
||
старое сохранение с четырьмя загруженными ракетами при загрузке ограничивается двумя.
|
||
- `2689d93`: документированы источники архитектуры батареи, команды, скриншоты и границы визуальной проверки.
|
||
|
||
## Проверки и воспроизведение
|
||
|
||
На `966b52f`: 169 тестов ядра + 4 сценария прошли, 7 ignored; адаптер — 53 теста,
|
||
1 boundary и 4 сценария прошли; WASM contract — 21 шаг. Это исходная контрольная точка,
|
||
не результат новых четырёх задач. На `2689d93` был собран чистый пакет (`airdef_dirty=false`).
|
||
|
||
На итоговом объединённом коде `6e2d661` прошли:
|
||
|
||
- `airdef-core --release`: **187 passed, 7 ignored**, плюс **4 сценария**.
|
||
- `airdef-mod`: **56 passed**, **1 boundary**, **4 сценария**.
|
||
- Настоящий WASM-пакет: **24 шага**, включая команды излучения и typed ammunition.
|
||
- `gen_models.py --check`: различий нет; в этой серии геометрия ассетов не менялась.
|
||
|
||
Полный core здесь запускался с `--release`; это не прогон всех семи ignored-тестов.
|
||
Отдельно выполнен сравнительный ignored-тест баланса (см. ниже).
|
||
|
||
```sh
|
||
cargo test --release --manifest-path airdef-core/Cargo.toml
|
||
cargo test --manifest-path airdef-mod/Cargo.toml
|
||
python3 tools/airdef.py test-wasm
|
||
python3 tools/gen_models.py --check
|
||
python3 tools/test_gen_assets.py
|
||
git diff --check
|
||
```
|
||
|
||
На этой macOS cargo находится в `~/.cargo/bin/cargo`. GUI-проверки запускать с отдельным
|
||
`HORIZON_HOME` и рабочим каталогом тестового мира; не использовать реальные сохранения владельца.
|
||
Metal-проверки не подтверждают Windows/Linux, HDR всех платформ или прослушивание звука.
|
||
Скриншоты крышек подтверждают только их позу: полного видео выброса/зажигания пока нет.
|
||
|
||
## Технические детали новой серии
|
||
|
||
### #120: энергетика и единственный исход перехвата
|
||
|
||
`MissileKind::burn_ticks` задаёт конечное время горения: простой профиль равен 2/3 игрового
|
||
`spec.life`; для электрического P1-SUN используется весь срок жизни. Это не отдельная модель
|
||
топлива и не реальные кривые тяги. `Missile::engine_lit` — общий источник состояния мотора.
|
||
|
||
Три ветки скорости разделены явно: cold (`age <= cold`, множитель 0.97 с прежним минимумом 0.4),
|
||
powered (`+accel`, ограничение `spec.speed`), coast (множитель 0.995 без холодного минимума).
|
||
После выгорания доступный поворот масштабируется текущей скоростью; при падении ниже 25%
|
||
игрового максимума перехват заканчивается диагностикой `MotorEnergyLost`. Срок жизни остаётся
|
||
отдельным ограничением. Полноценной аэродинамики, гравитационной баллистики и расхода топлива по тяге нет.
|
||
|
||
Swept fuse учитывает движение обоих объектов за тик; `Impact` получает точку closest approach
|
||
и относительную скорость того же проверенного отрезка, включая удержание на Unknown.
|
||
Геометрию не заменяет отдельный бонус «встречная/догонная». Один остаточный pk зависит от
|
||
фактической скорости перехватчика и существующего состояния носителя/дальности.
|
||
Повторный штраф по stealth и старый штраф по абсолютной скорости цели удалены из этого броска;
|
||
обнаружение/сопровождение по-прежнему учитывают stealth в своих местах.
|
||
|
||
`MotorBurnout` и `MotorEnergyLost` записываются в scene journal; tally отличает потерю энергии.
|
||
Live и replay прекращают факел и новый дым по одному состоянию. `Out::engine_stops` немедленно
|
||
снимает голос мотора на burnout, не ждёт обычной трёхтиковой grace пропавшего источника;
|
||
при переходе на replay/export live-команды остановки отбрасываются вместе с live-выводом.
|
||
Перемотка восстанавливает моторное состояние из записи, включая возврат до выгорания.
|
||
|
||
При ревью был найден и исправлен недостижимый coast: ранний прототип проверял `!lit`,
|
||
что перехватывало и cold, и coast. Не переносить один `143d9b2` без последующих исправлений.
|
||
`a7b8cb9` содержит отдельный тест точных правил скорости всех трёх фаз.
|
||
|
||
Сравнительная выборка **только изменения #120**, отдельно от #119/#118/#121:
|
||
baseline `2689d93`, агентская итоговая ветка `508f9a0` (её исправление перенесено как `a7b8cb9`).
|
||
12 одинаковых seed, `SAMS=20 SIZE=12`: 204 цели в каждой версии;
|
||
baseline — 202 сбитых, 2 прорыва, 367 ракет; новое — 203, 1, 355.
|
||
Это небольшой регрессионный ориентир, не доказательство баланса всех типов/дальностей.
|
||
Данные каждого seed: [CSV](measurements/issue-120-balance.csv).
|
||
|
||
```sh
|
||
SAMS=20 SIZE=12 cargo test --release --manifest-path airdef-core/Cargo.toml sim::balance::one_raid -- --ignored --nocapture
|
||
```
|
||
|
||
### #118: один физический груз и восстанавливаемая заявка
|
||
|
||
`ground_request` у С-400 — заявка на **одну** RM48U. Рядом со складом остаётся прямая передача;
|
||
вне радиуса склада та же команда `ground-load` создаёт заявку, если есть запас и живая ТЗМ.
|
||
ТЗМ забирает одну ракету из конечного запаса, едет к исправному развёрнутому носителю и передаёт
|
||
её в общие ячейки. Если вытеснена ракета ПВО, ТЗМ везёт её обратно на склад. Generic reload
|
||
не создаёт RM48U. Ударная заявка имеет приоритет перед generic reload.
|
||
|
||
Поля `ground_stock` / `air_48n6_stock` на складе — остатки, на ТЗМ — физический груз двух типов.
|
||
Заявка, груз и марш сохраняются; оперативный `job` реконструируется после загрузки.
|
||
Передача запрещена во время движения, подготовки пуска, перезарядки, отказа ПУ и при отсутствии
|
||
вместимости. Разрушение очищает заявку/груз; repair не восстанавливает уничтоженный typed stock.
|
||
Проверены настоящее движение `Sim.step` по плоскому WorldSource, передача/возврат, истощение,
|
||
прерывание, несовместимость, заполненные ячейки, unload и полный `state_text → apply_state`
|
||
с продолжением маршрута. GUI-доставка на сложном рельефе ещё не проверена.
|
||
|
||
Новых носителей вроде Бука не добавляли: один публичный игровой профиль не даёт основания
|
||
приписывать его всем ЗРК. Обратный вывоз RM48U из удалённого носителя пока не автоматизирован:
|
||
`ground-unload` требует склад рядом. Отдельной отмены ожидающей заявки в UI пока нет.
|
||
|
||
### #121: излучение отдельно от сети
|
||
|
||
`radar_on` — сохраняемая настройка, default=true для старых миров. Команда
|
||
`/airdef radar <номер> on|off` и кнопка карты меняют её; у launcher-only нет своего активного радара.
|
||
`radar_up` учитывает этот флаг. Off запрещает новые own measurements, но старые треки стареют
|
||
обычно и разрешённый сетевой приём сохраняется. Это не выключение корпуса/связи/ГСН ракеты.
|
||
Огневой радар, обязательный для отдельной ПУ, в Off не авторизует новые пуски.
|
||
|
||
Условный наблюдатель-противник раз в 20 тиков обнаруживает работающие радары в 1600 блоках.
|
||
Это упрощённый игровой датчик по расстоянию, без LOS/радиопеленгации и ошибки оценки позиции.
|
||
Контакт хранится как последняя наблюдённая точка и стареет за 6000 тиков. Off не стирает
|
||
контакт, не телепортирует его вслед за носителем и не предотвращает раскрытие пуском/РЭБ.
|
||
|
||
В `raid::radar_strikes` удалён отдельный обход: раньше SEAD выбирал любую Radar и её настоящий
|
||
`pos`, даже если общий planner уже работал по наблюдениям. Теперь SEAD берёт те же last-known
|
||
контакты и их возраст. Явный sandbox-режим `Aim::ObjectsAndSams` по-прежнему выбирает расстановку
|
||
напрямую; не путать его с умным противником. Проверки покрывают необнаруженную молчащую РЛС,
|
||
смену позиции без наблюдения, повторное раскрытие, старение, relay freshness и seek.
|
||
|
||
### Совместимость текстового состояния
|
||
|
||
Сохраняем строки `sam` расширением справа; индексы ниже включают слово `sam` как поле 0.
|
||
|
||
| Индекс | Значение |
|
||
|---|---|
|
||
| 22–24 | ground_rounds, ground_stock, air_48n6_stock |
|
||
| 25–27 | mode, radar_role, spent_cells |
|
||
| 28 | ground_request: 0/1, только С-400 |
|
||
| 29 | radar_on: true/false, отсутствие означает true |
|
||
|
||
Две агентские ветки сначала заняли поле 28 одновременно; при интеграции излучение перенесено
|
||
в 29, опубликованная совместимость заявки сохранена. Проверка полного roundtrip одновременно
|
||
содержит ожидающую доставку и выключенный радар. Новые значения входят в durable mark;
|
||
настройка излучения также в `SamKey` и ghost replay. Не переиспользовать эти позиции для нового поля.
|
||
|
||
### #119: непрямой взрыв и укрытия
|
||
|
||
`WorldCache::blast_cover` читает текущую occupancy без запросов мира и без загрузки чанков.
|
||
Три луча к репрезентативным точкам корпуса дают общий множитель для корпуса и узлов;
|
||
для отмеченного объекта считается своя тройка. Известное укрытие оставляет 15% игрового
|
||
воздействия по перекрытому лучу, открытый — 100%; края/проёмы дают промежуточное значение.
|
||
Все лучи этого вызова читаются до отправки разрушения в движок. Исходный воксель пропускается,
|
||
чтобы контакт на поверхности стены не закрывал взрыв сразу во все стороны.
|
||
|
||
Unknown, stale и слишком старые секции считаются **неразрешёнными**. Ожидание равно нулю:
|
||
для них сохраняется прежний неослабленный урон как консервативная игровая политика,
|
||
а не утверждение, что там воздух. После ответа мира этот взрыв не пересчитывается.
|
||
Нет очереди отложенного урона и повторного применения на world reply. Частичные блоки
|
||
на этом этапе считаются занятым кубом; тонкая collision shape для blast отдельно не запрашивается.
|
||
Прямой вооружённый контакт не ослабляется этим множителем.
|
||
|
||
Проверки `sim::damage::cover_tests`: стена/проём для корпуса, узлов и объекта;
|
||
Unknown и поздний ответ без повторного урона/запросов; прямое попадание; устаревшая геометрия;
|
||
пропуск исходного блока. Все четыре прошли в объединённом наборе.
|
||
|
||
## Что следующему агенту проверить в первую очередь
|
||
|
||
1. На Windows: обновление сабмодуля через `all`, сохранение/перезаход, рабочий цикл игры.
|
||
2. В GUI: полный холодный пуск крупным планом; карточка On/Off; маршрут ТЗМ по сложной местности;
|
||
разрушение стены одним взрывом и защита от того же взрыва по исходной геометрии.
|
||
3. Прослушать прекращение голоса двигателя при burnout и seek/экспорт вокруг этой границы.
|
||
4. Расширить баланс #120 на разные батареи, пределы дальности и классы целей; исходная CSV — ориентир.
|
||
5. Продолжить оставшиеся архитектурные #87/#88/#89/#91/#102 и художественный #115 по статусной таблице.
|
||
|
||
Это незавершённая платформенная/визуальная приёмка, а не отсутствие перечисленного выше кода.
|
||
Текущий прогон не запускал GUI или новый MP4, не прослушивал звук и не проверял Windows/Linux.
|
||
|
||
## Правила продолжения
|
||
|
||
- Не закрывать issue даже после исправления; сообщать проверенный объём и остаток в комментарии.
|
||
- Не переписывать gitlink на плавающую ветку. Изменения движка сначала публикуются отдельно.
|
||
- Не путать наблюдённый трек с настоящим положением цели и `own_tick` с relay.
|
||
- Не менять live-мир при seek; replay воспроизводит последствия, не применяет урон повторно.
|
||
- Не считать Unknown свободным пространством или подтверждённой стеной без явной игровой политики.
|
||
- Новые числа — игровой масштаб, не реальные характеристики вооружения.
|
||
- Токен Gitea читать из локального файла во время запроса; не коммитить и не печатать.
|