diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index cee63d9..1508ae8 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -121,6 +121,7 @@ - [x] **should** `combat-move-budget-not-consumed` — ~~бюджет движения в бою не списывается, кайтинг бесконечен~~ FIXED Sprint 024 phase 1 task 1, с переформулировкой: исходная премиса неверна, бюджет списывал диспетчер (`MOVE` = `cost_type=MOVEMENT`, `TurnBudget.consume` после хендлера), speed=30 через реальный диспетчер проходил ровно 30ft. Реальной проблемой был раздвоенный учёт — `MOVE` по запросу в диспетчере против `MOVE_TO`/`DASH` по факту в хендлере — с латентными багами диагонали (плоские 5 вместо 5/10) и частичного шага (списывался запрос, не пройденное). Ось движения унифицирована: `MOVE`→`cost_type=FREE`, `handle_move` списывает фактический `moved_ft` атомарно (reject целиком при нехватке), `CostType.MOVEMENT` удалён, `handle_move_to` различает «нет пути» и «не хватает движения», остаток движения и достижимость целей ушли в LLM-промпт. Инвариант: диспетчер владеет осью действий, `movement_remaining` — только movement-хендлеры. E2E: click-to-move списал 25 ft атомарно (30→5фт) - [x] **should** `npc-action-errors-leak-to-log` — ~~ошибки неудачных ходов НПС попадают в боевой лог игрока («Туда не пройти, путь заблокирован» от волка): `on_action` в `service/session.py` клал `msg["error"]` без фильтра по актору~~ FIXED Sprint 024 phase 1 task 2: сборка payload вынесена в `build_action_result` (`service/transport_payloads.py`), `error` и `budget` проставляются только когда актор — игрок. Post-audit E2E: свои отказы в логе видны, чужих технических нет - [ ] **could** `ui-language-mixing` — в английском UI серверные строки идут по `DND_LANGUAGE=ru`: combat log «Бой начался», «КЗ», «промах», тип NPC «человек» при английском shell UI. Язык клиента и сервера не согласован (сервер берёт env, клиент — свой). Сосед `npc-language`. E2E sprint 021 phase 2. Дополнено sprint 024: клиентское «КД» против серверного «КЗ» в одном экране (панель боя vs лог), «+2 str» в damage-breakdown при русской строке +- [ ] **should** `reaction-prompt-i18n` — модалка реакции (внеочередная атака) при `DND_LANGUAGE=ru` полностью английская: «Melee attack against Wolf». Найдено при `/update-docs` на закрытии sprint 024, не E2E — сценария на язык этой модалки нет. Цепочка: `round.py:446` собирает `ReactionOption.description` как f-строку мимо `gettext` (`round.py` вообще не импортирует `i18n`), `reaction_to_dict` (`transport_payloads.py:109`) прокидывает `option.description` сырой — в отличие от соседней строки 52, где описание действия оборачивается в `_(definition.description)`, — а `ReactionPrompt.tsx:32` рендерит как есть. Обёртка `_()` на транспорте не сработает: имя цели уже вставлено в строку, msgid не совпадёт. Фикс — либо строить описание через `_()` с плейсхолдером в момент конструирования (`_("Melee attack against %(target)s") % {...}`), либо передавать шаблон+params и склеивать на фронте по i18n-ключу (как сделано для `props` в sprint 024). Приоритет **should**, а не `could` как у соседнего `movement-log-i18n`: это не строка лога, а весь текст интерактивной модалки, блокирующей ход игрока. Семейство `ui-language-mixing`/`combat-log-i18n-gaps` - [ ] **should** `nearby-shows-raw-id` — панель «Поблизости» и aria-кнопки показывают raw entity id (`marta`, `gretta`, `aldric`) вместо display name («Гретта Торговка», «Сэр Олдрик» — имена есть: master-таблица и inspect-модалка их показывают), E2E sprint 024 post-audit. При этом лог событий корректно анонимизирует незнакомца до расы («человек говорит») — то есть панель ещё и подтекает мимо perceive(): игрок видит внутренний id существа, которого «не знает». Решить, что игрок должен видеть (display name или анонимную расу), и убрать id из player-facing payload - [ ] **could** `ru-duplicate-condition-label` — в форме редактирования существа (master) две кнопки состояний с одинаковой меткой «Оглушён»: Stunned и Deafened переведены одним словом (E2E sprint 024 post-audit). Deafened → «Оглохший»/«Глухота» в `.po` - [ ] **could** `combat-panel-weapon-summary-truncated` — строка «Оружие» в панели боя показывает только основной дайс («flaming slash (1d8)») без дополнительных компонентов урона (1d6 огненный), E2E sprint 024 post-audit. Карточка предмета и лог урона полные — сократили только тут; дорисовать полный damage-набор из `props`