feat(variants): default a registered account to Erudit + Russian Scrabble
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m16s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m53s

New Game opened on a single variant for everyone, which reads poorly on VK
where Russian Scrabble is the familiar game. A registered account now starts
with both Russian-alphabet games, so the picker offers a real choice with no
pre-selection.

A guest stays on Erudit alone and is invited to register for the rest: the
device-local guest has no profile at all, so the client-side fallback has to
keep matching the server. Registering promotes the set, but only while the
guest still carries the untouched guest default. Existing accounts are not
backfilled — the set they carry may be a deliberate choice.

The Telegram promo start-param becomes additive rather than a replacement,
with English Scrabble withheld from a Russian-speaking arrival; otherwise the
English campaign link would have taken Russian Scrabble away from every
account it onboarded.
This commit is contained in:
Ilia Denisov
2026-07-27 20:38:09 +02:00
parent 69b1a50644
commit b6d88da78c
19 changed files with 338 additions and 56 deletions
@@ -35,3 +35,37 @@ func TestSeedVariantsFromStartParam(t *testing.T) {
})
}
}
// TestMergeVariantSeed covers resolving what a promo-onboarded account should end up with:
// the seed only ever widens the current set, English Scrabble is withheld from a
// Russian-speaking arrival, and a merge that changes nothing reports nil so the caller
// skips the write.
func TestMergeVariantSeed(t *testing.T) {
promo := []string{"erudit_ru", "scrabble_en"} // the campaign link "verudit_ru-scrabble_en"
tests := []struct {
name string
current []string
seed []string
language string
want []string
}{
{"russian speaker keeps the default", DefaultVariantPreferences, promo, "ru", nil},
{"russian locale variant is still russian", DefaultVariantPreferences, promo, "ru-RU", nil},
{"english speaker gains english", DefaultVariantPreferences, promo, "en", []string{"erudit_ru", "scrabble_ru", "scrabble_en"}},
{"unsupported language is not russian", DefaultVariantPreferences, promo, "de", []string{"erudit_ru", "scrabble_ru", "scrabble_en"}},
{"absent language is not russian", DefaultVariantPreferences, promo, "", []string{"erudit_ru", "scrabble_ru", "scrabble_en"}},
{"no seed writes nothing", DefaultVariantPreferences, nil, "en", nil},
{"seed already covered writes nothing", DefaultVariantPreferences, []string{"scrabble_ru"}, "ru", nil},
{"the russian filter spares the account's own english", []string{"erudit_ru", "scrabble_en"}, promo, "ru", nil},
{"invalid seed writes nothing", DefaultVariantPreferences, []string{"chess"}, "en", nil},
{"a guest set is widened by the seed", GuestVariantPreferences, []string{"scrabble_ru"}, "ru", DefaultVariantPreferences},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := MergeVariantSeed(tc.current, tc.seed, tc.language)
if !slices.Equal(got, tc.want) {
t.Errorf("MergeVariantSeed(%v, %v, %q) = %v, want %v", tc.current, tc.seed, tc.language, got, tc.want)
}
})
}
}