feat: sparser robot nudges, typed unread badge, lobby unread bump
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 53s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m26s
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 53s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m26s
Three owner-requested polish changes: - robot: replace the lengthening 60-90 min -> 6 h proactive-nudge ramp with a flat uniform 9-12 h wait before every nudge; the existing sleep-window gate still skips and defers a nudge that would land in the robot's night. - ui: colour the lobby/in-game unread dot by type -- the regular danger colour when a chat message is unread, a softer amber (--warn) when only nudges are. Adds a per-viewer unread_messages flag (chat_messages.kind='message') across the backend DTO, FlatBuffers wire, gateway transcode and the UI store. - ui: float games with any unread notification to the top of the lobby's your-turn and opponent-turn sections (finished keeps its order), reusing the existing unread_chat flag. Docs (ARCHITECTURE 7, FUNCTIONAL + _ru) updated. No DB migration; the new wire field is backward-compatible.
This commit is contained in:
@@ -16,7 +16,8 @@ import (
|
||||
)
|
||||
|
||||
// TestChatUnreadAndMarkRead checks a text message marks every recipient seat unread (not the
|
||||
// sender), surfaces through HasUnread / UnreadGames, and that MarkRead clears the reader's bit.
|
||||
// sender), surfaces through HasUnread / UnreadGames and the message-level HasUnreadMessage /
|
||||
// UnreadMessageGames (it is a real message, not a nudge), and that MarkRead clears the reader's bit.
|
||||
func TestChatUnreadAndMarkRead(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc := newSocialService()
|
||||
@@ -37,6 +38,15 @@ func TestChatUnreadAndMarkRead(t *testing.T) {
|
||||
} else if !set[gameID] {
|
||||
t.Error("UnreadGames should include the game for the recipient")
|
||||
}
|
||||
// A text message also raises the message-level flags (it is not just a nudge).
|
||||
if msg, _ := svc.HasUnreadMessage(ctx, gameID, seats[1]); !msg {
|
||||
t.Error("recipient should have the message flagged as an unread message")
|
||||
}
|
||||
if set, err := svc.UnreadMessageGames(ctx, seats[1]); err != nil {
|
||||
t.Fatalf("unread message games: %v", err)
|
||||
} else if !set[gameID] {
|
||||
t.Error("UnreadMessageGames should include the game for a text message")
|
||||
}
|
||||
|
||||
// Reading it clears the recipient's bit and reports one entry marked.
|
||||
if n, err := svc.MarkRead(ctx, gameID, seats[1]); err != nil {
|
||||
@@ -55,7 +65,8 @@ func TestChatUnreadAndMarkRead(t *testing.T) {
|
||||
|
||||
// TestNudgeUnreadTargetsOnlyToMove checks, in a three-player game, that a nudge marks ONLY the
|
||||
// awaited (to-move) seat unread — never the other waiting players. This is the owner's nudge
|
||||
// targeting invariant, now observable through the unread bitmask.
|
||||
// targeting invariant, now observable through the unread bitmask. It also checks a nudge raises
|
||||
// HasUnread but not the message-level flags, so the badge can colour it apart from a real message.
|
||||
func TestNudgeUnreadTargetsOnlyToMove(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc := newSocialService()
|
||||
@@ -68,6 +79,13 @@ func TestNudgeUnreadTargetsOnlyToMove(t *testing.T) {
|
||||
if unread, _ := svc.HasUnread(ctx, gameID, seats[0]); !unread {
|
||||
t.Error("the awaited seat should have the nudge unread")
|
||||
}
|
||||
// A nudge is not a message: it must not raise the message-level flags.
|
||||
if msg, _ := svc.HasUnreadMessage(ctx, gameID, seats[0]); msg {
|
||||
t.Error("a nudge must not be flagged as an unread message")
|
||||
}
|
||||
if set, _ := svc.UnreadMessageGames(ctx, seats[0]); set[gameID] {
|
||||
t.Error("UnreadMessageGames must not include a game whose only unread entry is a nudge")
|
||||
}
|
||||
if unread, _ := svc.HasUnread(ctx, gameID, seats[2]); unread {
|
||||
t.Error("a non-awaited waiting seat must not receive the nudge")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user