From 74026223eefdbaec02436e79d3c9168a9ee0b906 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Wed, 15 Jul 2026 02:17:13 +0200 Subject: [PATCH] feat(account): give a fresh guest a distinct "Guest######" display name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every guest showed a bare "Guest" to opponents (e.g. in a random match). Mint the display name as "Guest" + a random six-digit suffix at provisioning, so guests are distinguishable. Not an identifier and not unique — a label only, so collisions are harmless. --- backend/internal/account/account.go | 12 +++++++++--- backend/internal/inttest/account_test.go | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/backend/internal/account/account.go b/backend/internal/account/account.go index 2324a2c..e4826d5 100644 --- a/backend/internal/account/account.go +++ b/backend/internal/account/account.go @@ -10,6 +10,7 @@ import ( "database/sql" "errors" "fmt" + "math/rand/v2" "strings" "time" @@ -525,8 +526,13 @@ func (s *Store) create(ctx context.Context, kind, externalID string, seed provis return created, nil } -// guestDisplayName is the display name stamped on a freshly provisioned guest. -const guestDisplayName = "Guest" +// guestDisplayName mints the display name stamped on a freshly provisioned guest: "Guest" plus a +// random six-digit suffix (e.g. "Guest042317"), so a guest is distinguishable to opponents — in a +// random match the other player sees a distinct name rather than every guest reading a bare +// "Guest". Not an identifier and not unique (collisions are harmless — it is a label only). +func guestDisplayName() string { + return fmt.Sprintf("Guest%06d", rand.IntN(1_000_000)) +} // ProvisionGuest creates a fresh ephemeral guest account: a durable row carrying // no identity, flagged is_guest, so it can hold a session and a game seat (both @@ -553,7 +559,7 @@ func (s *Store) ProvisionGuest(ctx context.Context, browserTZ, language string) } stmt := table.Accounts. INSERT(table.Accounts.AccountID, table.Accounts.DisplayName, table.Accounts.IsGuest, table.Accounts.TimeZone, table.Accounts.PreferredLanguage). - VALUES(accountID, guestDisplayName, true, tz, lang). + VALUES(accountID, guestDisplayName(), true, tz, lang). RETURNING(table.Accounts.AllColumns) var row model.Accounts diff --git a/backend/internal/inttest/account_test.go b/backend/internal/inttest/account_test.go index 5527741..fcbdb70 100644 --- a/backend/internal/inttest/account_test.go +++ b/backend/internal/inttest/account_test.go @@ -5,6 +5,7 @@ package inttest import ( "context" "errors" + "regexp" "testing" "time" @@ -241,6 +242,10 @@ func TestProvisionSeedsTimeZone(t *testing.T) { if guest.PreferredLanguage != "ru" { t.Errorf("guest PreferredLanguage = %q, want the seeded ru", guest.PreferredLanguage) } + // A guest's display name is "Guest" + a random six-digit suffix (distinct to opponents). + if m, _ := regexp.MatchString(`^Guest\d{6}$`, guest.DisplayName); !m { + t.Errorf("guest DisplayName = %q, want Guest + 6 digits", guest.DisplayName) + } plainGuest, err := store.ProvisionGuest(ctx, "", "") if err != nil { t.Fatalf("provision plain guest: %v", err)