feat(robot): per-game opponent names from a wide corpus + frozen seat-name snapshot #73

Merged
developer merged 3 commits from feature/robot-name-variety into development 2026-06-16 13:58:35 +00:00
Owner

Что и зачем

Имя соперника-робота было жёстко привязано к 64 «вечным» аккаунтам (1 аккаунт = 1 имя), оттого имена повторялись от партии к партии. Теперь:

  • Per-game имя: замаскированный робот авто-матча получает свежее имя на каждую партию, которое хранится в новом снимке места game_players.display_name.
  • Снимок фиксирует и живых игроков: имя соперника заморожено на время партии — позднейшее переименование больше не переписывает прошлые партии. Для строк без снимка (до миграции) — фолбэк на текущее имя аккаунта.
  • Широкий корпус (internal/robot/namevariety.go): западные локали (EN/DE/ES/IT/FR/PT), родные японские/китайские имена, расширенный русский пул и «человеческие» ники. Маршрутизация в духе Pick: русская партия — кириллица + ≤20% латиницы, без CJK; английская — весь корпус. Через robot.PickNamed.
  • Послабление валидации account.ValidateDisplayName (и зеркало ui/src/lib/profileValidation.ts): разрешён хвост из ≤5 цифр, так что ники вида «Player2007» валидны и для человека — замаскированный робот остаётся неотличимым (ARCHITECTURE §7).

Контракты / риски

  • Публичный контракт ввода: правило display_name ослаблено (цифры хвостом ≤5). Backend + UI-зеркало + тесты синхронизированы.
  • Persistence: миграция 00007_seat_display_name.sqlаддитивная (ADD COLUMN ... NOT NULL DEFAULT ''), без бэкфилла; jet перегенерирован. Совместима со старой БД контура (goose донакатит 00007), вайп схемы не требуется.
  • Поведение: honest-AI (vs_ai) без изменений (имя аккаунта, GCG = «AI»); число роботов прежнее (64) — «толпу» делают per-game имена.

Проверка (локально, всё зелёное)

  • backend: build / vet / gofmt; весь unit; весь -tags=integration (testcontainers).
  • UI: pnpm check (0 ошибок) / test:unit (266) / build.
  • Новые тесты: инвариант «каждое сгенерённое имя проходит ValidateDisplayName», маршрутизация скриптов по варианту, заморозка имени после переименования, round-trip per-game имени робота.

Визуальная приёмка

После деплоя на тестовый контур — несколько авто-матчей в EN- и RU-партиях (разные имена соперников; RU без CJK; EN с JP/CN) и проверка профиля (имя с хвостом цифр сохраняется, цифра в середине / >5 цифр — отклоняется).

## Что и зачем Имя соперника-робота было жёстко привязано к 64 «вечным» аккаунтам (1 аккаунт = 1 имя), оттого имена повторялись от партии к партии. Теперь: - **Per-game имя**: замаскированный робот авто-матча получает **свежее имя на каждую партию**, которое хранится в новом снимке места `game_players.display_name`. - **Снимок фиксирует и живых игроков**: имя соперника заморожено на время партии — позднейшее переименование больше не переписывает прошлые партии. Для строк без снимка (до миграции) — фолбэк на текущее имя аккаунта. - **Широкий корпус** (`internal/robot/namevariety.go`): западные локали (EN/DE/ES/IT/FR/PT), родные японские/китайские имена, расширенный русский пул и «человеческие» ники. Маршрутизация в духе `Pick`: русская партия — кириллица + ≤20% латиницы, **без CJK**; английская — весь корпус. Через `robot.PickNamed`. - **Послабление валидации** `account.ValidateDisplayName` (и зеркало `ui/src/lib/profileValidation.ts`): разрешён **хвост из ≤5 цифр**, так что ники вида «Player2007» валидны и для человека — замаскированный робот остаётся неотличимым (`ARCHITECTURE §7`). ## Контракты / риски - **Публичный контракт ввода**: правило `display_name` ослаблено (цифры хвостом ≤5). Backend + UI-зеркало + тесты синхронизированы. - **Persistence**: миграция `00007_seat_display_name.sql` — **аддитивная** (`ADD COLUMN ... NOT NULL DEFAULT ''`), без бэкфилла; jet перегенерирован. Совместима со старой БД контура (goose донакатит 00007), **вайп схемы не требуется**. - **Поведение**: honest-AI (`vs_ai`) без изменений (имя аккаунта, GCG = «AI»); число роботов прежнее (64) — «толпу» делают per-game имена. ## Проверка (локально, всё зелёное) - backend: `build` / `vet` / `gofmt`; весь unit; весь `-tags=integration` (testcontainers). - UI: `pnpm check` (0 ошибок) / `test:unit` (266) / `build`. - Новые тесты: инвариант «каждое сгенерённое имя проходит `ValidateDisplayName`», маршрутизация скриптов по варианту, заморозка имени после переименования, round-trip per-game имени робота. ## Визуальная приёмка После деплоя на тестовый контур — несколько авто-матчей в EN- и RU-партиях (разные имена соперников; RU без CJK; EN с JP/CN) и проверка профиля (имя с хвостом цифр сохраняется, цифра в середине / >5 цифр — отклоняется).
developer added 1 commit 2026-06-16 10:29:09 +00:00
feat(robot): per-game display names from a wide name corpus
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 48s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m10s
183e08ec80
Decouple the displayed opponent name from the small pool of durable robot
accounts: the disguised auto-match robot now gets a freshly composed name each
game, stamped on a new game_players.display_name seat snapshot. The snapshot
also captures humans' names, freezing what an opponent sees for the life of a
game (a later rename no longer rewrites past games); readers fall back to the
account's current name for pre-migration rows.

Names come from a wide composed corpus (internal/robot/namevariety.go): Western
locales (EN/DE/ES/IT/FR/PT), native Japanese/Chinese names, a gender-agreed
Russian pool, and human-style handles. Routing keeps Pick's spirit -- a Russian
game draws Cyrillic + <=20% Latin and never a CJK script; an English game the
full corpus -- via robot.PickNamed.

Loosen account.ValidateDisplayName (and the UI mirror) to admit a trailing run
of up to five digits, so "Player2007"-style handles are valid for humans too
and the disguised robot stays indistinguishable.

Migration 00007 adds game_players.display_name (additive, NOT NULL DEFAULT '');
jet regenerated. Docs (ARCHITECTURE 7, FUNCTIONAL + _ru, PLAN, README) updated.
developer added 1 commit 2026-06-16 13:22:34 +00:00
fix(robot): show the per-game name in REST game views, not the account name
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 50s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m18s
6d66545062
The seat display-name snapshot only reached the live-event path (seatNames);
the REST DTO layer still resolved seat names from the account store
(fillSeatNames), so the game screen and lobby list showed the robot's seeded
account name ("Женя") while the your_turn toast showed its per-game name
("Звёздный_Барс2"). Carry the snapshot into gameDTOFromGame and have
fillSeatNames fall back to the account only for a seat with no snapshot (a
pre-snapshot legacy row). Friends and invitations keep account names (the
persistent identity, not a per-game disguise).
developer added 1 commit 2026-06-16 13:51:10 +00:00
feat(robot): gender-agree Cyrillic handle adjectives
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 49s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m12s
14b5f61af9
Cyrillic adjective+noun handles paired a masculine adjective with any noun, so a
feminine noun read ungrammatically ("Вольный Комета"). Carry masculine + feminine
adjective forms (cyrAdjective) and tag each noun's gender (cyrNoun); cyrillicNick
now renders the adjective in the agreeing form ("Рыжая Комета", "Дикий Волк"), and a
few feminine nouns (Комета/Звезда/Молния/Пантера/Рысь/Буря/Сова/Акула) are added for variety.
owner approved these changes 2026-06-16 13:57:11 +00:00
developer merged commit 51d7c4e005 into development 2026-06-16 13:58:35 +00:00
developer deleted branch feature/robot-name-variety 2026-06-16 13:58:35 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#73