docs: analyze card movement animation regressions
CI / test (push) Successful in 3m0s
Details
CI / test (push) Successful in 3m0s
Details
This commit is contained in:
parent
6395680344
commit
aac0268cf2
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
| ID | Статус | Название | Фаза | Проверка |
|
| ID | Статус | Название | Фаза | Проверка |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| — | — | Нет активных задач | — | — |
|
| TASK-2026-001 | `[ ]` | Плавность карточных перемещений и корректные источники | DeepSeek: анализ готов; Kimi: ожидает | не выполнена |
|
||||||
|
|
||||||
Новые задачи добавляются в конец файла отдельными разделами. Не используй один
|
Новые задачи добавляются в конец файла отдельными разделами. Не используй один
|
||||||
раздел для нескольких независимых задач.
|
раздел для нескольких независимых задач.
|
||||||
|
|
@ -120,3 +120,333 @@
|
||||||
- **Не завершено/заблокировано:** ...
|
- **Не завершено/заблокировано:** ...
|
||||||
- **Skill обновлён:** да/нет, почему.
|
- **Skill обновлён:** да/нет, почему.
|
||||||
- **Git:** commit hash, изменённые файлы.
|
- **Git:** commit hash, изменённые файлы.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TASK-2026-001 — Плавность карточных перемещений и корректные источники
|
||||||
|
|
||||||
|
- **Статус:** `[ ]`
|
||||||
|
- **Создано:** 2026-10-24
|
||||||
|
- **Анализ:** DeepSeek выполнен
|
||||||
|
- **Реализация:** Kimi, не начата
|
||||||
|
- **Проверка:** не выполнена
|
||||||
|
- **Затронутые системы:** `GameBoard3D`, `Card3D`, `CardMoveAnimator`,
|
||||||
|
`BattleView`, `AnimationConfig`, EditMode-тесты.
|
||||||
|
|
||||||
|
#### A. Цель и требования
|
||||||
|
|
||||||
|
Пользователь сообщил: анимации движения карт «отрабатывают рвано»,
|
||||||
|
запускаются ненужные анимации, карты двигаются не из нужных позиций. Нужно
|
||||||
|
исправить именно презентационный слой, не меняя правила игры.
|
||||||
|
|
||||||
|
Ожидаемое поведение:
|
||||||
|
|
||||||
|
- анимация запускается только при реальном переходе карты между зонами/слотами
|
||||||
|
или при изменении позы, а не при каждом UI-рендере;
|
||||||
|
- источник анимации — фактическая старая зона/поза карты (рука, поле, Trigger,
|
||||||
|
Damage, Drop, Soul, Guardian, Deck), а не всегда колода;
|
||||||
|
- рубашка/лицо источника учитываются: карта из колоды начинает движение
|
||||||
|
рубашкой вверх, а не лицом;
|
||||||
|
- повторный снапшот или локальный `Render` не создаёт второй запрос на ту же
|
||||||
|
карту и не откатывает её в середину пути;
|
||||||
|
- скрытые карты (рука противника, закрытый урон) не пересоздаются и не летят
|
||||||
|
из колоды на каждом `Render`;
|
||||||
|
- существующие правила, серверные контракты, `InputLockService`, пул карт и
|
||||||
|
публичные визуальные эффекты не ломаются.
|
||||||
|
|
||||||
|
Ограничения:
|
||||||
|
|
||||||
|
- не менять `GameEngine`, правила, сервер, протокол и YAML-контент;
|
||||||
|
- не добавлять DOTween/UniTask/новые пакеты;
|
||||||
|
- не менять сцены/префабы без отдельного решения;
|
||||||
|
- не переписывать `CardMoveAnimator` на другой animation stack;
|
||||||
|
- геймплей вручную проверяет пользователь; автотесты показывают только
|
||||||
|
техническую корректность.
|
||||||
|
|
||||||
|
#### B. Текущее состояние и найденные причины
|
||||||
|
|
||||||
|
Проверены:
|
||||||
|
|
||||||
|
- `client/Assets/Vanguard/Runtime/Board3D/View/GameBoard3D.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/Board3D/Animation/CardMoveAnimator.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/Board3D/View/Card3D.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/Board3D/Data/BoardTypes.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/Board3D/Logic/PlaymatLayout.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/UI/BattleView.cs`;
|
||||||
|
- `client/Assets/Vanguard/Runtime/Battle/AnimationConfig.cs`;
|
||||||
|
- `client/Assets/Vanguard/Resources/AnimationConfig.asset`;
|
||||||
|
- `client/Assets/Vanguard/Tests/Editor/GameBoard3DTests.cs`.
|
||||||
|
|
||||||
|
Факты:
|
||||||
|
|
||||||
|
1. **Скрытые карты с `InstanceId = 0` пересоздаются.** В
|
||||||
|
`GameBoard3D.AddOpponentHandSpecs` (`OH:player:i`) и
|
||||||
|
`GameBoard3D.AddDamageSpecs` (`D:player:i`) для скрытых карт
|
||||||
|
`BoardCardRef.InstanceId` равен `0`. В `GameBoard3D.Render` распределение
|
||||||
|
старых карт идёт только через `previousByInstance` и условие
|
||||||
|
`spec.Ref.InstanceId != 0`. Поэтому при каждом `Render` такие карты
|
||||||
|
арендуются заново, старые освобождаются, а новые получают `moved = true` и
|
||||||
|
анимацию из `SourcePose`.
|
||||||
|
2. **`BattleView.Render()` вызывается не только на снапшот.** Локальные
|
||||||
|
действия (выбор guard, меню карты, подтверждение, статус) тоже вызывают
|
||||||
|
`BattleView.Render` → `GameBoard3D.Render`. В сочетании с п.1 это даёт
|
||||||
|
«ненужные анимации» на каждый клик.
|
||||||
|
3. **`SourcePose` всегда использует колоду.** Метод
|
||||||
|
`GameBoard3D.SourcePose` возвращает `_layout.DeckPosition(localSeat)` и
|
||||||
|
базовый yaw без состояния лица. Новая карта, пришедшая из Soul, Drop,
|
||||||
|
Guardian, Trigger или Damage, начинает полёт из колоды; карта из колоды
|
||||||
|
начинает путь лицом вверх, хотя должна быть рубашкой вверх.
|
||||||
|
4. **У Damage ключ по индексу, а не по личности.** `D:player:i` остаётся тем
|
||||||
|
же при смене открытой карты или при открытии закрытой. Текущий branch
|
||||||
|
`sameInstance` освобождает старую карту и создаёт новую с `SourcePose`
|
||||||
|
(колода), хотя это может быть переворот/смена карты на месте.
|
||||||
|
5. **Нет coalescing в `CardMoveAnimator`.** `Enqueue` не отменяет старый
|
||||||
|
queued/active request той же `Card3D`. Если карта успевает сменить зону до
|
||||||
|
старта предыдущего запроса, второй запрос может стартовать из устаревшей
|
||||||
|
позиции; активная запись при этом может остаться в `_active`.
|
||||||
|
6. **`Card3D.SetPose` не является точкой начала движения.** Для существующей
|
||||||
|
карты `Render` вызывает `SetPose` (меняет target), затем `Enqueue`; для
|
||||||
|
новой карты `PlaceImmediate` + `SetPose`. При повторном `Render` target
|
||||||
|
может быть обновлён до/после старта, а старый arc не всегда
|
||||||
|
согласован с новым request.
|
||||||
|
7. **Конфиг анимаций не синхронизирован с кодом.** В
|
||||||
|
`AnimationConfig.asset` нет новых полей `moveDuration`,
|
||||||
|
`importantMoveDuration`, `moveDelayBetweenCards`, `arcHeight`, camera/arrow
|
||||||
|
полей, хотя они объявлены в `AnimationConfig.cs`. Нужно проверить
|
||||||
|
фактические значения после импорта Unity; нельзя считать asset
|
||||||
|
настроенным, пока поля не сериализованы.
|
||||||
|
8. **`UpdateHandView` каждый кадр делает `SetPose` для руки.** Это может
|
||||||
|
перетирать target во время движения карты в руку и мешать стабильности
|
||||||
|
arc; нужно проверить и, если подтверждено, не менять target у карты,
|
||||||
|
которая уже летит, либо синхронизировать target с move request.
|
||||||
|
9. **Пул карт и `InputLock` уже имеют защиту** (`CancelCard`, таймаут,
|
||||||
|
`CancelAll`); её нельзя удалять. Исправления должны сохранить отсутствие
|
||||||
|
вечного `card-move`-лока.
|
||||||
|
|
||||||
|
Что сохранить:
|
||||||
|
|
||||||
|
- `GameBoard3D` как единственный рендер-дифф и владелец пула;
|
||||||
|
- `CardMoveAnimator` как единый планировщик;
|
||||||
|
- `Card3D` как визуальную карту и arc-интерполяцию;
|
||||||
|
- `InputLockService` и существующие long-running последовательности;
|
||||||
|
- серверный snapshot как источник состояния.
|
||||||
|
|
||||||
|
#### C. Чек-лист изменений
|
||||||
|
|
||||||
|
- [ ] **C1. `MODIFY` `GameBoard3D.Render`** — стабильная идентичность
|
||||||
|
анонимных карт.
|
||||||
|
- Файл: `client/Assets/Vanguard/Runtime/Board3D/View/GameBoard3D.cs`.
|
||||||
|
- В `CardAssignment` добавить признак `ReuseByKey`/`StateOnly` (имя выбрать
|
||||||
|
по стилю файла).
|
||||||
|
- Если `_cards` уже содержит `spec.Key` — переиспользовать эту `Card3D`
|
||||||
|
даже при `InstanceId == 0`; не вызывать `RentCard`.
|
||||||
|
- Для `InstanceId == 0` не ставить `moved = true` только из-за отсутствия
|
||||||
|
записи в `previousByInstance`.
|
||||||
|
- При смене `InstanceId` 0→real в том же слоте (открытие урона) сохранить
|
||||||
|
карту, обновить art/bind/face state; не отправлять её в полёт из колоды.
|
||||||
|
- При исчезновении ключа освобождать карту как раньше.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C2, C4.
|
||||||
|
|
||||||
|
- [ ] **C2. `MODIFY` `GameBoard3D.AddOpponentHandSpecs` /
|
||||||
|
`AddDamageSpecs`** — стабильные ключи и явная политика анимации.
|
||||||
|
- Файл: `client/Assets/Vanguard/Runtime/Board3D/View/GameBoard3D.cs`.
|
||||||
|
- Оставить `OH:player:i` для скрытой руки и `D:player:i` для слота урона;
|
||||||
|
не использовать `InstanceId=0` как личность.
|
||||||
|
- Для скрытых карт при стабильном ключе не анимировать; при добавлении
|
||||||
|
новой скрытой карты в конец — разрешить один переход из Deck.
|
||||||
|
- Для урона: смена 0↔real или real→real в том же слоте — обновление
|
||||||
|
карты/переворот, не новый полёт из Deck.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1.
|
||||||
|
|
||||||
|
- [ ] **C3. `MODIFY` `GameBoard3D` — карта источника из предыдущего
|
||||||
|
`MatchView`.**
|
||||||
|
- Файл: `client/Assets/Vanguard/Runtime/Board3D/View/GameBoard3D.cs`.
|
||||||
|
- Сохранять предыдущий `MatchView`/его зоны до присваивания нового
|
||||||
|
`_view`.
|
||||||
|
- Построить `Dictionary<int, SourcePose>` для `Hand`, `Guardian`, `Soul`,
|
||||||
|
`Drop`, `Trigger`, `FaceUpDamage` (и при необходимости field), где
|
||||||
|
`SourcePose` содержит position/rotation/scale/faceUp.
|
||||||
|
- `SourcePose(spec)`: приоритет — текущая `Card3D` (для transfer), затем
|
||||||
|
previous-view зона по `InstanceId`, затем `DeckPosition`.
|
||||||
|
- Источники:
|
||||||
|
- Deck: `DeckPosition`, рубашка вверх (rotation с X-flip);
|
||||||
|
- Soul: `SoulPosition`, лицом вверх;
|
||||||
|
- Drop: `DropPosition`, лицом вверх;
|
||||||
|
- Guardian: фактическая `Card3D` или `GuardianPosition`, +90°;
|
||||||
|
- Trigger: фактическая `Card3D` или `TriggerPosition`, ±90°;
|
||||||
|
- FaceUpDamage: `DamagePosition`, лицом вверх и на боку;
|
||||||
|
- Hand: карта в руке, лицом вверх;
|
||||||
|
- Field: фактическая `Card3D`/`CirclePosition`.
|
||||||
|
- Не придумывать источник, если `InstanceId` нет в previous view и он не
|
||||||
|
Deck: fallback Deck допустим только с комментарием/тестом.
|
||||||
|
- `PlaceImmediate` для нового источника должен получать rotation с
|
||||||
|
правильным flip, а не только yaw.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1, C2.
|
||||||
|
|
||||||
|
- [ ] **C4. `MODIFY` `CardMoveAnimator.Enqueue`** — один активный/queued
|
||||||
|
request на карту.
|
||||||
|
- Файл: `client/Assets/Vanguard/Runtime/Board3D/Animation/CardMoveAnimator.cs`.
|
||||||
|
- Перед постановкой нового request отменять/удалять старый request этой же
|
||||||
|
`Card3D` (queued и active), не трогая другие карты.
|
||||||
|
- Новый request должен начинаться с текущей визуальной позиции карты, а не
|
||||||
|
со старого `FromPosition`; если target совпадает — не создавать запрос.
|
||||||
|
- Не допускать дублей в `_active`; сохранить timeout/`CancelCard`/
|
||||||
|
`CancelAll` и снятие `card-move`-лока.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1.
|
||||||
|
|
||||||
|
- [ ] **C5. `MODIFY` `GameBoard3D.Render` + `BattleView.Render`** — явно
|
||||||
|
различать snapshot-рендер и локальный UI-рендер.
|
||||||
|
- Файлы: `GameBoard3D.cs`, `client/Assets/Vanguard/Runtime/UI/BattleView.cs`.
|
||||||
|
- Добавить параметр `animateMoves` (или эквивалентный options-объект) без
|
||||||
|
публичного изменения серверных DTO.
|
||||||
|
- `OnSnapshot` → `animateMoves: true`.
|
||||||
|
- Локальные `Render()` (guard selection, card menu, status, cost counter) →
|
||||||
|
`animateMoves: false`: обновлять highlight/UI, но не запускать новые
|
||||||
|
move-анимации и не менять идентичность карт.
|
||||||
|
- Если при локальном Render карта реально новая (не должно происходить),
|
||||||
|
поставить в target pose без анимации и записать warning в debug-лог.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1, C2.
|
||||||
|
|
||||||
|
- [ ] **C6. `MODIFY` `Card3D` / `GameBoard3D.UpdateHandView`** — не
|
||||||
|
перетирать движение руки.
|
||||||
|
- Файлы: `client/Assets/Vanguard/Runtime/Board3D/View/Card3D.cs`,
|
||||||
|
`GameBoard3D.cs`.
|
||||||
|
- Проверить сценарий «карта летит из Deck в Hand»: `UpdateHandView`
|
||||||
|
вызывает `SetPose` каждый кадр; target должен совпадать с target request.
|
||||||
|
- Если подтверждено расхождение — обновлять target request при изменении
|
||||||
|
hand pose или не вызывать `SetPose` для карты, которая ещё в
|
||||||
|
`CardMoveAnimator.IsBusy` для этого instance.
|
||||||
|
- Не отключать руку от камеры и не менять `GetHandViewPose` без
|
||||||
|
необходимости.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C3, C4.
|
||||||
|
|
||||||
|
- [ ] **C7. `MODIFY` `AnimationConfig.asset` + проверка значений.**
|
||||||
|
- Файл: `client/Assets/Vanguard/Resources/AnimationConfig.asset`.
|
||||||
|
- Добавить/сериализовать `moveDuration`, `importantMoveDuration`,
|
||||||
|
`moveDelayBetweenCards`, `arcHeight`, camera/grow/dash-поля из
|
||||||
|
`AnimationConfig.cs`.
|
||||||
|
- Зафиксировать разумные значения: движение ~0.4–0.6, важное ~0.8–1.0,
|
||||||
|
stagger ~0.15–0.25, arc ~0.3–0.5; не менять длительности feedback без
|
||||||
|
запроса.
|
||||||
|
- Проверить в Unity Inspector, что значения не нулевые и совпадают с кодом.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C5 (можно параллельно).
|
||||||
|
|
||||||
|
- [ ] **C8. `TEST` `GameBoard3DTests`** — регрессии анимаций.
|
||||||
|
- Файл: `client/Assets/Vanguard/Tests/Editor/GameBoard3DTests.cs`.
|
||||||
|
- Добавить тесты:
|
||||||
|
1. повторный `Render` с тем же view/state не увеличивает число
|
||||||
|
`Card3D` для opponent hand/face-down damage;
|
||||||
|
2. повторный `Render` не создаёт новый `CardMoveAnimator` request для
|
||||||
|
стабильного ключа;
|
||||||
|
3. открытие face-down damage переиспользует `Card3D` и не отправляет его
|
||||||
|
из Deck;
|
||||||
|
4. новый unit из hand сохраняет source-позицию руки, а не Deck;
|
||||||
|
5. `CardMoveAnimator` coalesce: второй Enqueue той же карты не оставляет
|
||||||
|
дубль в active/queue;
|
||||||
|
6. `CancelCard` по-прежнему освобождает `card-move`-лок.
|
||||||
|
- Для проверки source/queue при необходимости добавить **тестовый seam**
|
||||||
|
(read-only snapshot последних запросов/позиций) в `CardMoveAnimator` или
|
||||||
|
`GameBoard3D`, не меняя публичное поведение.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1–C6.
|
||||||
|
|
||||||
|
- [ ] **C9. `VERIFY` smoke / compile / EditMode.**
|
||||||
|
- Запустить EditMode в копии проекта без `Library`.
|
||||||
|
- `PLAYMAT_SMOKE`; `SCENE_SMOKE` — если затронуты сцены/сборка.
|
||||||
|
- Проверить отсутствие ошибок компиляции и предупреждений о missing
|
||||||
|
serialized fields.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена.
|
||||||
|
- Зависит от: C1–C8.
|
||||||
|
|
||||||
|
- [ ] **C10. `VERIFY` ручная проверка пользователем.**
|
||||||
|
- Пользователь проверяет: draw, call, ride, move/swap, guard, trigger,
|
||||||
|
drive/damage, retire, search, открытие скрытого урона, руку противника,
|
||||||
|
повторные клики по UI во время/после анимации.
|
||||||
|
- Ожидаемо: нет полёта скрытых карт из колоды при каждом клике; источник
|
||||||
|
совпадает с зоной; нет рывков/двойных стартов; ввод не зависает.
|
||||||
|
- Реализация: не выполнена.
|
||||||
|
- Проверка: не выполнена — только пользователь.
|
||||||
|
- Зависит от: C9.
|
||||||
|
|
||||||
|
#### D. Последовательность выполнения
|
||||||
|
|
||||||
|
1. C1 + C2: стабилизировать идентичность/ключи, убрать пересоздание скрытых
|
||||||
|
карт. Без этого остальные исправления будут маскировать симптом.
|
||||||
|
2. C3: добавить source map и корректные source pose/face. Проверить Deck,
|
||||||
|
Hand, Trigger, Damage, Soul/Drop/Guardian.
|
||||||
|
3. C4: coalescing в аниматоре и отмена старого request.
|
||||||
|
4. C5: разделить snapshot/UI-рендер, убрать лишние запуски.
|
||||||
|
5. C6: проверить hand target; не менять без подтверждённой необходимости.
|
||||||
|
6. C7: синхронизировать asset.
|
||||||
|
7. C8: тесты; C9: проверки; C10: ручная проверка пользователя.
|
||||||
|
|
||||||
|
#### E. Проверки
|
||||||
|
|
||||||
|
- Client EditMode: `GameBoard3DTests` + новые тесты из C8.
|
||||||
|
- Compile/Assembly: Unity batch mode в копии без `Library`.
|
||||||
|
- Smoke: `Vanguard.Editor.SceneSmoke.RunPlaymat`; `Run` только при изменении
|
||||||
|
сцен/сборки.
|
||||||
|
- `git diff --check`, просмотр `git diff`, отсутствие изменений в
|
||||||
|
Rules/Server/Shared/Content.
|
||||||
|
- Повторный `Render` с неизменным view: число карт и move-request не растёт.
|
||||||
|
- Повторный snapshot во время движения: нет двойного старта/сброса в
|
||||||
|
источник.
|
||||||
|
- Ручная проверка — пользователем; не заменять её автотестом.
|
||||||
|
|
||||||
|
Команды (подтверждены проектом):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# клиентская копия без Library
|
||||||
|
& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' `
|
||||||
|
-batchmode -nographics -projectPath <copy> `
|
||||||
|
-runTests -testPlatform EditMode -testResults <copy>\TestResults.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
Серверные тесты не требуются, если не меняются Rules/Server/Shared; при
|
||||||
|
изменении контрактов — только `ssh home`/Docker.
|
||||||
|
|
||||||
|
#### F. Риски и неизвестные вопросы
|
||||||
|
|
||||||
|
- **Анонимные карты:** `InstanceId=0` не является уникальной личностью;
|
||||||
|
нельзя использовать его для глобального map. Нужны стабильные ключи по
|
||||||
|
зоне/индексу и отдельная политика для reveal.
|
||||||
|
- **Источник вне видимых зон:** Deck не содержит `InstanceId`; для карты из
|
||||||
|
колоды источник всегда Deck. Для карты из Soul/Drop/Guardian/Trigger/Damage
|
||||||
|
источник можно восстановить из previous view; иначе fallback Deck.
|
||||||
|
- **Смена открытого урона:** при перестановке face-up damage возможна
|
||||||
|
неоднозначность. Не анимировать перемещение между слотами урона, если это
|
||||||
|
не подтверждено; приоритет — не «телепорт из колоды».
|
||||||
|
- **`AnimationConfig.asset`:** после добавления полей Unity может сохранить
|
||||||
|
старые значения; проверить Inspector, не считать defaults автоматически
|
||||||
|
настроенными.
|
||||||
|
- **`UpdateHandView`:** если менять target каждый кадр, можно ухудшить
|
||||||
|
плавность; C6 требует подтверждения тестом/наблюдением, а не слепой правки.
|
||||||
|
- **Не менять** `CardMoveAnimator` timeout/`CancelCard`/`CancelAll` без
|
||||||
|
сохранения защиты от зависшего `InputLock`.
|
||||||
|
- **Не расширять** задачу на рефакторинг `BattleView` или замену animation
|
||||||
|
stack.
|
||||||
|
|
||||||
|
#### G. Результат
|
||||||
|
|
||||||
|
- **Реализовано:** не начато.
|
||||||
|
- **Проверки:** не выполнены.
|
||||||
|
- **Не завершено/заблокировано:** ожидает этапа Kimi; критических вопросов
|
||||||
|
пользователю на данный момент нет.
|
||||||
|
- **Skill обновлён:** не требуется до подтверждения новых постоянных правил.
|
||||||
|
- **Git:** изменён только план/документация, код не менялся.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue