Files
airdef/docs/CODEX-HANDOFF.md
T
chexit d410e2c92d
build / mod (push) Failing after 18s
docs: archive the reproduced fuel failure and bounded cache fix
Preserve the diagnostic trigger, scenario, before/after logs and scope of equivalent counters. Update ground strike guidance, Windows acceptance status and profiler semantics.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:39:23 +03:00

34 KiB
Raw Blame History

Передача разработки AirDef

Это журнал фактически сделанных изменений и ограничений проверки, а не список обещанных функций. Рабочая ветка kimi-work; issues не закрывать, публиковать комментарии с коммитом и проверками. Движок — отдельный chexit/horizon-airdef, ветка airdef, подключён точным gitlink horizon/.

Текущее состояние: 3 ноября 2026

Код предыдущих четырёх задач интегрирован до 6e2d661. Продолжение #102/обратного вывоза опубликовано до aab3e78; последнее продолжение расследования налётов — 2932364. Текущий движок — f95f03c08ec2916a0e5bd3b2d4a2a790e7937b47, API 27. 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.

Продолжение #102 и обратного вывоза RM48U

  • d3378b3: fork() синхронизирует URL из .gitmodules даже на fast path совпавшего pin. Реальная Git-регрессия воспроизводит старый upstream URL и новый коммит, отсутствующий в локальном clone. Это исправляет наблюдавшееся на Windows upload-pack: not our ref 86b1014…; пользователь подтвердил ручное исправление через git submodule sync --recursive до публикации автоматизации.
  • bb931ab, e9fbaba, b0085cb: ground-unload вдали от склада резервирует одну RM48U и вызывает ТЗМ. ground-cancel отменяет ещё ожидающий вывоз/доставку; после забора груз продолжает путь на склад. Проверены физическое движение и полный save/restore до забора и после забора, без телепортации запаса.
  • 910f02c: потеря зарезервированной ракеты вместе с ячейками сбрасывает заявку на вывоз. Иначе можно было создать сохранение, которое loader сам отвергал как несовместимое состояние.
  • Двигатель: f4c1131d3, затем c89c78c47 опубликованы в horizon-airdef:airdef до обновления gitlink. API27 добавляет acoustics-status и capture-owner-status, scoped к запуску мода и поколению мира. Остановка capture проверяет владельца; смена мира снимает незапущенный запрос или посылает cancel.
  • 910f02c: команда /airdef capabilities; дальний звуковой fallback сохраняется до подготовки акустического пути, экспорт принимает только своё подтверждённое состояние; Arming ждёт до 600 тиков. prepared — milestone хоста, не GPU fence, не результат каждой акустической трассы и не готовый MP4.
  • 4dddea2, 8d5d0d1: opt-in test-budgets, отдельный ручной workflow и JSON provenance; тесты ошибок сборки, stale identity и ненулевого runtime exit. Native success не заменяет actual WASM.
  • aab3e78: repo-local packer использует target-cache закреплённого движка; CARGO_TARGET_DIR не переопределяется для сборки самого мода и не уводит .hmod в чужое дерево.

Проверки объединённого состояния: core release 190 + 4 сценария, 7 ignored; адаптер 60 + 1 boundary + 4 сценария; лёгкий WASM 26 шагов, тяжёлый 69 шагов; Git-регрессия и три теста failure report прошли. Исходный профиль запрашивал 64 ПВО + 160 целей, 602 tick / 300 frame; JSON фиксирует clean aab3e78, pin API27 и совпадающий build identity. Полные данные: budget report. Исправление оценки покрытия: второй запрос исходного 69-шагового сценария отклонялся во время подготовки первого. Его успешный exit не подтверждает 160 запущенных или одновременно летящих целей. В архивный JSON добавлена поправка; исправленный сценарий проверяет ответы. Для настоящего stress также нужны ответы render-world: прежний sandbox их не давал и часто проверял лишь ожидание земли.

Дополнительно два свежих профиля игры на Metal/no-audio: smoke off не ready, HD smoke ready; при HORIZON_ACOUSTICS=1 + HORIZON_NO_AUDIO=1 акустика enabled/request=true, prepared=false, awaiting-backend. Выход через quit подтверждён. Это не прослушивание, не benchmark и не новый MP4. Правила API, пределы проверок и команды: ENGINE.md.

Двойные налёты и плотность следов

Перед продолжением читать RAID-STABILITY.md: один соответствующий класс отключения теперь воспроизведён и исправлен (1f28f83), приёмка конкретного Windows-сеанса остаётся. Текущий исправленный WASM stress проверяет две принятые волны, обслуживаемую плоскую геометрию и 184 воздушные цели в конкретный момент; новый JSON заменяет прежнее недостаточное доказательство покрытия. Лимиты fuel/memory не увеличивались. 86e1d272e в движке улучшает callback/fuel/error-chain diagnostics; ed7615d36 добавляет только необязательную flat-world среду тестов и отказывает неожиданным ошибкам команд в Script. Основная клиентская логика сцены этим test helper не заменяется.

692ae77: HD-треки ракет оптически плотнее на 12% через общий rocket() и cruise style. SAM/RM48U, крылатые/сверхзвуковые/баллистические треки покрыты; сегментов, радиусов и времени не добавлено. Пожары и дымка винтовых дронов не менялись. Обычные ванильные fallback-частицы этим множителем не меняются. Пять существующих smoke-тестов прошли; прирост FPS и приёмка новой плотности на Windows не заявлены.

Последний общий прогон: core release190 + 6 сценариев, 7 ignored; адаптер60 + 1 boundary + 4 сценария; лёгкий WASM26; тяжёлый WASM271; 5 тестов отчёта. Нативные overlap-тесты — airdef-core/tests/scenarios.rs: два стандартных массовых пресета и два налёта с разделением «Орешников», оба со встроенной записью.

Продолжение по пользовательскому HD-отключению: 1f28f83 заменяет полный known.retain при каждом взрыве на удаление прежнего квадрата; семантическая эквивалентность проверена. В диагностическом WASM max-menu ×2 раньше был trap tick1835 на 300M; после фикса полный 3602-tick прогон прошёл, max135273690. Гость отличается от baseline только временным trigger hook состава меню и исправлением. Это измерение fuel, не прирост FPS. Артефакты/ограничения — в RAID-STABILITY. cc48302 добавляет публичный native max-menu regression; 3b470dd закрепляет опциональный engine test --fuel-profile (не новый SDK API и не увеличение лимитов).

cbd6067 исправляет сообщение о пустом соседнем складе, показывает типизированные запасы на M, уточняет подсказку разведки и убирает устаревшую строку README о якобы отсутствующей доставке. GROUND-STRIKES.md — инструкция с различием номеров своего С-400/склада и вражеской ПУ. Default RM48U=0; ground-stock задаёт остаток, ground-load грузит одну; поздний трек не даёт fix. ab737e7: actual WASM теперь 27 шагов с проверкой ошибки пустого соседнего склада.

После фикса полный core: 192 passed + 6 сценариев / 7 ignored; новый max-menu сценарий отдельно прошёл седьмым. Адаптер60 + 1 boundary + 4 сценария; light WASM27; engine /spin fuel-profile test прошёл.

Исходная контрольная точка этой серии

Исходное состояние этой серии: 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-тест баланса (см. ниже).

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.

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-доставка на сложном рельефе ещё не проверена.

Новых носителей вроде Бука не добавляли: один публичный игровой профиль не даёт основания приписывать его всем ЗРК. Обратный вывоз из удалённого носителя автоматизирован в продолжении выше. Новая команда ground-cancel отменяет ожидающую заявку, но не возвращает уже забранный груз в ПУ. ТЗМ вмещает два типизированных места RM48U/48Н6; прежние абстрактные generic reload-пакеты учитываются отдельно. Вывезенная ракета возвращается в конечный запас; ПВО восстанавливается при заборе только из реально имеющейся у ТЗМ ракеты 48Н6 и свободной ячейки. Резерв одной RM48U учитывается при выборе носителя удара.

#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
30 ground_return: true/false, резерв вывоза одной RM48U из С-400
31 return_cargo: true/false, возвращаемая RM48U на ТЗМ

Две агентские ветки сначала заняли поле 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. В продолжении API27 есть два коротких игровых smoke, но новый MP4, прослушивание и платформенная приёмка Windows/Linux по-прежнему не выполнены.

Правила продолжения

  • Не закрывать issue даже после исправления; сообщать проверенный объём и остаток в комментарии.
  • Не переписывать gitlink на плавающую ветку. Изменения движка сначала публикуются отдельно.
  • Не путать наблюдённый трек с настоящим положением цели и own_tick с relay.
  • Не менять live-мир при seek; replay воспроизводит последствия, не применяет урон повторно.
  • Не считать Unknown свободным пространством или подтверждённой стеной без явной игровой политики.
  • Новые числа — игровой масштаб, не реальные характеристики вооружения.
  • Токен Gitea читать из локального файла во время запроса; не коммитить и не печатать.