mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
Retired agents (agent.archived_at set) previously read as offline across the agent dot, hover card, detail badge, and squad member list — a leftover online runtime row could even make them look reachable. Add a dedicated archived presence/status that wins over every runtime/task signal so a retired agent never reads as live or merely offline. - Add archived to AgentAvailability and SquadMemberStatusValue unions - Short-circuit deriveAgentPresenceDetail before runtime/task scan - Backend deriveSquadMemberStatus returns archived instead of offline - Render gray Archive dot/label; skip workload + reassign affordances - en/ko/zh-Hans locale strings
53 lines
2.0 KiB
Go
53 lines
2.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
func TestDeriveSquadMemberStatus(t *testing.T) {
|
|
now := time.Date(2026, 5, 18, 12, 0, 0, 0, time.UTC)
|
|
online := pgtype.Text{String: "online", Valid: true}
|
|
offline := pgtype.Text{String: "offline", Valid: true}
|
|
missing := pgtype.Text{}
|
|
|
|
tsAgo := func(d time.Duration) pgtype.Timestamptz {
|
|
return pgtype.Timestamptz{Time: now.Add(-d), Valid: true}
|
|
}
|
|
tsNone := pgtype.Timestamptz{}
|
|
|
|
cases := []struct {
|
|
name string
|
|
archived bool
|
|
runtimeStatus pgtype.Text
|
|
lastSeen pgtype.Timestamptz
|
|
hasActiveTask bool
|
|
want string
|
|
}{
|
|
{"active wins over offline runtime", false, offline, tsAgo(time.Hour), true, "working"},
|
|
{"active wins over missing runtime", false, missing, tsNone, true, "working"},
|
|
{"online runtime, no task", false, online, tsAgo(2 * time.Second), false, "idle"},
|
|
{"offline runtime, recent heartbeat", false, offline, tsAgo(2 * time.Minute), false, "unstable"},
|
|
{"offline runtime, stale heartbeat", false, offline, tsAgo(2 * time.Hour), false, "offline"},
|
|
{"offline runtime, no heartbeat", false, offline, tsNone, false, "offline"},
|
|
{"no runtime row", false, missing, tsNone, false, "offline"},
|
|
// Archived agents always report archived regardless of any leftover
|
|
// runtime row or task — they should appear in the squad listing
|
|
// but never look like they're still working or merely offline.
|
|
{"archived agent with active task", true, online, tsAgo(time.Second), true, "archived"},
|
|
{"archived agent with online runtime", true, online, tsAgo(time.Second), false, "archived"},
|
|
{"archived agent already offline", true, offline, tsAgo(time.Hour), false, "archived"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := deriveSquadMemberStatus(tc.archived, tc.runtimeStatus, tc.lastSeen, tc.hasActiveTask, now)
|
|
if got != tc.want {
|
|
t.Fatalf("deriveSquadMemberStatus = %q, want %q", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|