import { describe, expect, test } from "bun:test"; import { creatorAnnouncement, creatorHue, creatorInitials, creatorLabel, railRowCreator, } from "./creator-initials"; import { buildRailForest, channelRailSections, summarizeRailNodes, summarizeRailStatusCounts, sessionProjectTotals, } from "./sessions-group"; import type { Session } from "../types"; // channelRailSections only reads id / parentSessionId / status / channelId / // timestamps off the sessions inside the forest, so a bounded fixture keeps // this focused without replaying the whole Session contract. function session(patch: Partial & Pick): Session { return { accountId: "account-1", workspaceId: "workspace-1", status: "idle", initialMessage: "hi", title: null, parentSessionId: null, channelId: null, pinned: false, pinnedAt: null, pinVersion: 0, createdBy: { kind: "subject", subjectId: "user:test" }, effectiveControl: activeControl(), createdAt: "2026-08-01T00:00:00.000Z", updatedAt: "2026-08-01T00:00:00.000Z", ...patch, } as Session; } function activeControl(): Session["effectiveControl"] { return { state: "active", controlVersion: 0, controlEtag: "active-0", directState: "active", primaryBlocker: null, additionalBlockerCount: 0, blockers: [], resumeOptions: [], override: null, settlement: null, }; } function pausedControl(): Session["effectiveControl"] { const blocker = { kind: "session" as const, sessionId: "paused", displayName: "Paused here", actor: null, reason: null, changedAt: null, revision: 1, }; return { ...activeControl(), state: "paused", controlVersion: 1, controlEtag: "paused-1", directState: "paused", primaryBlocker: blocker, blockers: [blocker], resumeOptions: [], }; } const CHANNELS = [ { id: "channel-knowledge", name: "knowledge" }, { id: "channel-security", name: "security" }, ]; test("complete project summaries replace loaded counts and clear empty groups", () => { const groups = sessionProjectTotals( { needsYouCount: 9, groups: [ { channelId: "channel-security", total: 80, attention: 9, attentionSince: "2026-08-01T00:00:00.000Z", failed: 2, active: 4, queued: 3, unread: 20, activeWork: 1, }, ], }, CHANNELS.map((channel) => channel.id), ); expect( summarizeRailStatusCounts(groups.get("channel-security")!, new Date("2026-08-01T01:00:00Z")), ).toMatchObject({ kind: "needs_attention", count: 9, total: 80 }); expect(summarizeRailStatusCounts(groups.get("channel-knowledge")!)).toMatchObject({ kind: "neutral", total: 0, }); expect( summarizeRailStatusCounts({ ...groups.get("channel-security")!, sendFailed: 1 }), ).toMatchObject({ kind: "send_failed", count: 1, total: 80 }); expect( sessionProjectTotals( { needsYouCount: 0, groups: [{ ...groups.get("channel-security")!, channelId: "removed-project" }], }, [], ).get(null)?.total, ).toBe(80); }); test("project totals split parked waits out of the server's working count", () => { const group = { channelId: "channel-security", total: 3, attention: 0, attentionSince: null, failed: 0, active: 2, queued: 0, unread: 0, activeWork: 0, }; const totals = (waiting?: number) => sessionProjectTotals( { needsYouCount: 0, groups: [{ ...group, ...(waiting === undefined ? {} : { waiting }) }] }, ["channel-security"], ).get("channel-security")!; expect(summarizeRailStatusCounts(totals(2))).toMatchObject({ kind: "waiting", count: 2 }); expect(summarizeRailStatusCounts(totals(1))).toMatchObject({ kind: "active", count: 1 }); // An older server without the field keeps the previous working marker. expect(summarizeRailStatusCounts(totals())).toMatchObject({ kind: "active", count: 2 }); }); describe("channelRailSections", () => { test("puts projects in channel order before unfiled Default", () => { const forest = buildRailForest([ session({ id: "s-unfiled" }), session({ id: "s-security", channelId: "channel-security" }), session({ id: "s-running", channelId: "channel-security", status: "running" }), ]); const sections = channelRailSections(forest, CHANNELS); expect(sections.map((section) => section.key)).toEqual([ "channel-knowledge", "channel-security", "default", ]); // knowledge stays visible while empty; security floats its running root first. expect(sections[0]!.sessions).toEqual([]); expect(sections[1]!.sessions.map((node) => node.session.id)).toEqual([ "s-running", "s-security", ]); expect(sections[2]!.name).toBe("Default"); expect(sections[2]!.channelId).toBeNull(); expect(sections[2]!.sessions.map((node) => node.session.id)).toEqual(["s-unfiled"]); }); test("omits empty Default and folds unknown project ids into it otherwise", () => { const filedOnly = channelRailSections( buildRailForest([session({ id: "s-1", channelId: "channel-security" })]), CHANNELS, ); expect(filedOnly.some((section) => section.channelId === null)).toBe(false); const orphaned = channelRailSections( buildRailForest([session({ id: "s-orphan", channelId: "channel-deleted" })]), CHANNELS, ); const defaultSection = orphaned.find((section) => section.channelId === null); expect(defaultSection?.key).toBe("default"); expect(defaultSection?.sessions.map((node) => node.session.id)).toEqual(["s-orphan"]); }); test("renders a newly-created session under its project without a transient Default section", () => { const project = { id: "channel-new", name: "New project" }; const sections = channelRailSections( buildRailForest([session({ id: "new-session", channelId: project.id })]), [project], ); expect(sections.map((section) => section.key)).toEqual([project.id]); expect(sections[0]?.sessions.map((node) => node.session.id)).toEqual(["new-session"]); expect(sections.some((section) => section.channelId === null)).toBe(false); }); test("children stay nested under their root's channel section", () => { const forest = buildRailForest([ session({ id: "root", channelId: "channel-security" }), session({ id: "child", parentSessionId: "root" }), ]); const sections = channelRailSections(forest, CHANNELS); const security = sections.find((section) => section.channelId === "channel-security"); expect(security?.sessions).toHaveLength(1); expect(security?.sessions[0]!.children.map((node) => node.session.id)).toEqual(["child"]); // The unfiled child must not surface as its own Default root. expect(sections.some((section) => section.channelId === null)).toBe(false); }); }); describe("summarizeRailNodes", () => { test("shows a local message delivery failure without calling the session failed", () => { const forest = buildRailForest([session({ id: "delivery-failed", status: "idle" })]); const nodes = forest.grouped.flatMap((bucket) => bucket.sessions); expect(summarizeRailNodes(nodes, new Map([["delivery-failed", 2]]))).toEqual({ kind: "send_failed", count: 2, total: 1, label: "2 messages not sent", }); expect(nodes[0]?.session.status).toBe("idle"); }); test("keeps a loaded child's local failure visible through server tree stats", () => { const forest = buildRailForest([ session({ id: "root", treeStats: { directChildren: 1, totalDescendants: 1, runningDescendants: 0, queuedDescendants: 0, attentionDescendants: 0, pausedDescendants: 0, failedDescendants: 0, truncated: false, }, }), session({ id: "child", parentSessionId: "root" }), ]); const nodes = forest.grouped.flatMap((bucket) => bucket.sessions); expect(summarizeRailNodes(nodes, new Map([["child", 1]]))).toEqual({ kind: "send_failed", count: 1, total: 2, label: "1 message not sent", }); }); test("uses the highest-priority hidden descendant state", () => { const forest = buildRailForest([ session({ id: "root", status: "idle", treeStats: { directChildren: 4, totalDescendants: 4, runningDescendants: 1, queuedDescendants: 1, attentionDescendants: 1, pausedDescendants: 0, failedDescendants: 1, truncated: false, }, }), ]); const summary = summarizeRailNodes(forest.running); expect(summary).toEqual({ kind: "needs_attention", count: 1, total: 5, label: "1 needs you", }); }); test("treats capacity waits as waiting to run, not as active execution", () => { const forest = buildRailForest([session({ id: "waiting", status: "waiting_capacity" })]); expect(summarizeRailNodes(forest.running)).toMatchObject({ kind: "queued", label: "1 waiting to run", }); }); test("does not count a paused queued child as working", () => { const forest = buildRailForest([ session({ id: "root" }), session({ id: "paused", parentSessionId: "root", status: "queued", effectiveControl: pausedControl(), }), ]); const nodes = forest.grouped.flatMap((bucket) => bucket.sessions); expect(forest.running).toEqual([]); expect(summarizeRailNodes(nodes)).toEqual({ kind: "neutral", count: 0, total: 2, label: "Read", }); }); test("shows an acknowledged terminal section with no status marker", () => { const forest = buildRailForest([session({ id: "one" }), session({ id: "two" })]); const nodes = forest.grouped.flatMap((bucket) => bucket.sessions); expect(summarizeRailNodes(nodes)).toEqual({ kind: "neutral", count: 0, total: 2, label: "Read", }); }); test("shows a failed task in red only until that viewer has acknowledged it", () => { const unreadFailure = buildRailForest([ session({ id: "failed-unread", status: "failed", unread: true }), ]); expect(summarizeRailNodes(unreadFailure.grouped[0]!.sessions)).toEqual({ kind: "failed", count: 1, total: 1, label: "1 failed", }); const reviewedFailure = buildRailForest([ session({ id: "failed-reviewed", status: "failed", unread: false }), ]); expect(summarizeRailNodes(reviewedFailure.grouped[0]!.sessions)).toEqual({ kind: "neutral", count: 0, total: 1, label: "Read", }); }); test("does not keep a parent red for an acknowledged failed descendant", () => { const forest = buildRailForest([ session({ id: "root-with-reviewed-failure", treeStats: { directChildren: 1, totalDescendants: 1, runningDescendants: 0, queuedDescendants: 0, attentionDescendants: 0, pausedDescendants: 0, failedDescendants: 1, unreadFailedDescendants: 0, unreadDescendants: 0, activelyWorkingDescendants: 0, truncated: false, }, }), ]); expect(summarizeRailNodes(forest.grouped[0]!.sessions)).toEqual({ kind: "neutral", count: 0, total: 2, label: "Read", }); }); test("solid unread wins over the actively-working follow-up label", () => { const forest = buildRailForest([ session({ id: "one", unread: true, activelyWorking: true }), session({ id: "two", activelyWorking: true }), ]); const nodes = forest.grouped.flatMap((bucket) => bucket.sessions); expect(summarizeRailNodes(nodes)).toEqual({ kind: "unread", count: 1, total: 2, label: "1 unread", }); }); test("queued output stays unread but exposes the unread label only after settling", () => { const queued = session({ id: "answered", status: "queued", unread: true }); expect(summarizeRailNodes(buildRailForest([queued]).running)).toMatchObject({ kind: "queued", label: "1 waiting to run", }); expect(queued.unread).toBe(true); const settled = buildRailForest([{ ...queued, status: "idle" }]); expect(summarizeRailNodes(settled.grouped.flatMap((group) => group.sessions))).toMatchObject({ kind: "unread", label: "1 unread", }); }); }); describe("creatorInitials", () => { test("derives two-letter monograms from labels and subject ids", () => { expect( creatorInitials({ kind: "subject", subjectId: "user:x", label: "Davlet Dzhakishev" }), ).toBe("DD"); expect(creatorInitials({ kind: "subject", subjectId: "user:x", label: "iuliia" })).toBe("IU"); expect(creatorInitials({ kind: "subject", subjectId: "user:bendik" })).toBe("BE"); }); test("hides machinery: service and unattributed-legacy creators get none", () => { expect(creatorInitials({ kind: "service", subjectId: "scheduled-task" })).toBeNull(); expect(creatorInitials({ kind: "subject", subjectId: "unattributed-legacy" })).toBeNull(); }); test("hue is stable per subject and in range", () => { const hue = creatorHue("user:test"); expect(hue).toBe(creatorHue("user:test")); expect(hue).toBeGreaterThanOrEqual(0); expect(hue).toBeLessThan(360); }); }); describe("railRowCreator", () => { const createdBy = { kind: "subject", subjectId: "user:bendik", label: "Bendik" } as const; test("a top-level session offers its creator", () => { expect(railRowCreator({ parentSessionId: null, createdBy })).toBe(createdBy); }); test("a spawned session offers none: it inherits its parent's creator", () => { expect(railRowCreator({ parentSessionId: "manager", createdBy })).toBeNull(); }); }); describe("creatorAnnouncement", () => { test("announces only creators whose chip actually renders", () => { expect(creatorAnnouncement({ kind: "subject", subjectId: "user:x", label: "Ada" })).toBe("Ada"); expect(creatorAnnouncement(null)).toBeNull(); expect(creatorAnnouncement({ kind: "service", subjectId: "scheduled-task" })).toBeNull(); expect(creatorAnnouncement({ kind: "subject", subjectId: "unattributed-legacy" })).toBeNull(); }); }); describe("creatorLabel", () => { test("prefers a trimmed label and falls back to the subject id", () => { expect(creatorLabel({ kind: "subject", subjectId: "user:x", label: " Bendik " })).toBe( "Bendik", ); expect(creatorLabel({ kind: "subject", subjectId: "user:x", label: " " })).toBe("user:x"); expect(creatorLabel({ kind: "subject", subjectId: "user:x" })).toBe("user:x"); }); }); describe("summarizeRailNodes waiting duration", () => { const NOW = new Date("2026-08-22T12:00:00.000Z"); const hoursAgo = (hours: number) => new Date(NOW.getTime() - hours * 3_600_000).toISOString(); test("says how long the longest-waiting hidden descendant has needed input", () => { const forest = buildRailForest([ session({ id: "root", status: "idle", treeStats: { directChildren: 3, totalDescendants: 3, runningDescendants: 0, queuedDescendants: 0, attentionDescendants: 2, pausedDescendants: 0, failedDescendants: 0, attentionSince: hoursAgo(10), truncated: false, }, }), ]); expect(summarizeRailNodes(forest.running, new Map(), NOW)).toEqual({ kind: "needs_attention", count: 2, total: 4, label: "2 need you · 10h", attentionSince: hoursAgo(10), }); }); test("takes the earliest wait across the node's own turn and its descendants", () => { const forest = buildRailForest([ session({ id: "root", status: "requires_action", requiresActionSince: hoursAgo(2), treeStats: { directChildren: 1, totalDescendants: 1, runningDescendants: 0, queuedDescendants: 0, attentionDescendants: 1, pausedDescendants: 0, failedDescendants: 0, attentionSince: hoursAgo(26), truncated: false, }, }), session({ id: "other-root", status: "requires_action", requiresActionSince: hoursAgo(5), }), ]); const nodes = [...forest.running, ...forest.grouped.flatMap((bucket) => bucket.sessions)]; expect(summarizeRailNodes(nodes, new Map(), NOW)).toMatchObject({ kind: "needs_attention", count: 3, label: "3 need you · 26h", attentionSince: hoursAgo(26), }); }); test("keeps the plain label when no server reported a waiting timestamp", () => { const forest = buildRailForest([session({ id: "root", status: "requires_action" })]); const nodes = [...forest.running, ...forest.grouped.flatMap((bucket) => bucket.sessions)]; const summary = summarizeRailNodes(nodes, new Map(), NOW); expect(summary.label).toBe("1 needs you"); expect("attentionSince" in summary).toBe(false); }); });