Skip to content
361 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { AgentSession, InboxItem } from "@g1t/contracts";
5
6import {
7 type AttentionRow,
8 type CodeNeed,
9 type CodePull,
10 acceptance,
11 agentRow,
12 attention,
13 chatRow,
14 codeRow,
15 dayIn,
16 daySentence,
17 dayWork,
18 daysBefore,
19 notificationRow,
20 pullOutcome,
21 rankAttention,
22 sessionOutcome,
23 spendToday,
24 startHere,
25 trendLabel,
26 waitingSentence,
27} from "./today.ts";
28
29const HOUR = 3_600_000;
30const DAY = 24 * HOUR;
31// Friday 2026-10-09, 18:00 UTC; 11:00 in Los Angeles.
32const NOW = Date.parse("2026-10-09T18:00:00Z");
33const LA = "America/Los_Angeles";
34const repo = { namespace: "acme", name: "web" };
35const iso = (ms: number) => new Date(ms).toISOString();
36
37function pull(over: Partial<CodePull> = {}): CodePull {
38 return {
39 repo,
40 number: 1,
41 title: "Fix the flaky test",
42 status: "merged",
43 mergedAt: iso(NOW - HOUR),
44 createdAt: iso(NOW - 3 * HOUR),
45 updatedAt: iso(NOW - HOUR),
46 author: { username: "g1t", kind: "agent" },
47 ...over,
48 };
49}
50
51function session(over: Partial<AgentSession> = {}): AgentSession {
52 return {
53 id: "s1",
54 workspace_id: "w",
55 agent_id: "a",
56 agent_handle: "margo",
57 agent_name: "Margo",
58 agent_avatar_seed: "margo",
59 subagent: null,
60 kind: "chat",
61 parent_id: null,
62 root_id: "s1",
63 payer_agent_id: "a",
64 title: "Draft the launch notes",
65 goal: "",
66 status: "done",
67 status_note: null,
68 summary: null,
69 channel_id: "c",
70 channel_kind: "channel",
71 channel_name: "launch",
72 card_message_id: null,
73 asked_by: null,
74 asked_by_username: "bo",
75 routine_id: null,
76 steps: 3,
77 tool_calls: 2,
78 input_tokens: 0,
79 output_tokens: 0,
80 charged_micros: 400_000,
81 cap_micros: 2_000_000,
82 model: null,
83 outputs: [],
84 created_at: iso(NOW - 2 * HOUR),
85 updated_at: iso(NOW - HOUR),
86 finished_at: iso(NOW - HOUR),
87 visible: true,
88 ...over,
89 };
90}
91
92test("today is the reader's day, and the seven days before it", () => {
93 assert.equal(dayIn(NOW, LA), "2026-10-09");
94 assert.equal(dayIn(Date.parse("2026-10-10T02:00:00Z"), LA), "2026-10-09");
95 assert.equal(dayIn(Date.parse("2026-10-10T02:00:00Z"), null), "2026-10-10");
96 assert.equal(dayIn(NOW, "Not/AZone"), "2026-10-09");
97 assert.deepEqual(daysBefore(NOW, LA, 3), ["2026-10-08", "2026-10-07", "2026-10-06"]);
98});
99
100test("an agent's pull request is accepted first time when it merged today with no revision", () => {
101 assert.equal(pullOutcome(pull(), 0, "2026-10-09", null), "accepted");
102 assert.equal(pullOutcome(pull(), 2, "2026-10-09", null), "fixed");
103 assert.equal(pullOutcome(pull({ mergedAt: iso(NOW - DAY) }), 0, "2026-10-09", null), null);
104 assert.equal(pullOutcome(pull({ status: "closed", mergedAt: null }), 0, "2026-10-09", null), "dropped");
105 assert.equal(pullOutcome(pull({ status: "open", mergedAt: null }), 1, "2026-10-09", null), "open");
106 assert.equal(pullOutcome(pull({ status: "draft", mergedAt: null, updatedAt: iso(NOW - 2 * DAY) }), 0, "2026-10-09", null), null);
107});
108
109test("a session counts once, at the root of its tree, and is never 'accepted'", () => {
110 assert.equal(sessionOutcome(session(), "2026-10-09", null), "finished");
111 assert.equal(sessionOutcome(session({ parent_id: "s0" }), "2026-10-09", null), null);
112 assert.equal(sessionOutcome(session({ status: "failed" }), "2026-10-09", null), "dropped");
113 assert.equal(sessionOutcome(session({ status: "stopped" }), "2026-10-09", null), "dropped");
114 assert.equal(sessionOutcome(session({ status: "working", finished_at: null }), "2026-10-09", null), "open");
115 assert.equal(sessionOutcome(session({ status: "needs_approval", finished_at: null, updated_at: iso(NOW - 3 * DAY) }), "2026-10-09", null), null);
116 assert.equal(sessionOutcome(session({ finished_at: iso(NOW - DAY) }), "2026-10-09", null), null);
117});
118
119test("accepted first time is accepted over every agent pull request that settled", () => {
120 assert.deepEqual(acceptance(["accepted", "accepted", "fixed", "dropped", "open", "finished"]), { value: 0.5, of: 4 });
121 assert.equal(acceptance(["open", "finished"]), null);
122});
123
124test("the day's work: pull requests and sessions, sources, and the week before", () => {
125 const work = dayWork({
126 now: NOW,
127 timeZone: null,
128 slug: "acme",
129 code: {
130 pulls: [
131 pull({ number: 1 }),
132 pull({ number: 2 }),
133 pull({ number: 3, status: "open", mergedAt: null }),
134 // A person's pull request is not agent work.
135 pull({ number: 4, author: { username: "bo", kind: "user" } }),
136 // The week before: one accepted, one fixed.
137 pull({ number: 5, mergedAt: iso(NOW - 2 * DAY), updatedAt: iso(NOW - 2 * DAY) }),
138 pull({ number: 6, mergedAt: iso(NOW - 3 * DAY), updatedAt: iso(NOW - 3 * DAY) }),
139 // Older than a week: not counted.
140 pull({ number: 7, mergedAt: iso(NOW - 9 * DAY), updatedAt: iso(NOW - 9 * DAY) }),
141 ],
142 revisions: { "acme/web#2": 1, "acme/web#6": 2 },
143 complete: true,
144 },
145 sessions: { sessions: [session(), session({ id: "s2", kind: "routine", status: "working", finished_at: null }), session({ id: "s3", parent_id: "s1" })], complete: true },
146 });
147 assert.equal(work.tasks.length, 5);
148 assert.deepEqual(work.counts, { accepted: 1, fixed: 1, finished: 1, open: 2, dropped: 0 });
149 assert.deepEqual(work.rate, { value: 0.5, of: 2 });
150 assert.deepEqual(work.lastWeek, { value: 0.5, of: 2 });
151 assert.deepEqual(work.sources, [
152 { source: "code", count: 3 },
153 { source: "chat", count: 1 },
154 { source: "schedule", count: 1 },
155 ]);
156 // Open work goes last on the strip.
157 assert.deepEqual(work.tasks.slice(-2).map((t) => t.outcome), ["open", "open"]);
158 assert.equal(work.code, "read");
159 assert.equal(work.partial, false);
160 assert.equal(daySentence(work), "Agents finished 3 tasks. 1 needed a fix after review, and 2 are still open.");
161});
162
163test("no trend when the week could not all be read, and none without Code", () => {
164 const partial = dayWork({ now: NOW, timeZone: null, slug: "acme", code: { pulls: [pull()], revisions: {}, complete: false }, sessions: null });
165 assert.equal(partial.lastWeek, null);
166 assert.equal(partial.partial, true);
167 assert.equal(partial.sessions, "unavailable");
168 const member = dayWork({ now: NOW, timeZone: null, slug: "acme", code: "no_access", sessions: { sessions: [session()], complete: true } });
169 assert.equal(member.code, "no_access");
170 assert.equal(member.rate, null);
171 assert.equal(member.tasks.every((t) => t.source !== "code"), true);
172});
173
174test("the trend is in whole points", () => {
175 assert.equal(trendLabel({ value: 0.89 }, { value: 0.83 }), "+6 pts vs the last 7 days");
176 assert.equal(trendLabel({ value: 0.5 }, { value: 0.75 }), "−25 pts vs the last 7 days");
177 assert.equal(trendLabel({ value: 0.5 }, { value: 0.5 }), "Same as the last 7 days");
178 assert.equal(trendLabel(null, { value: 0.5 }), null);
179});
180
181test("the sentence for a quiet day, and for what waits", () => {
182 const quiet = dayWork({ now: NOW, timeZone: null, slug: "acme", code: { pulls: [], revisions: {}, complete: true }, sessions: { sessions: [], complete: true } });
183 assert.equal(daySentence(quiet), "No agent work today yet.");
184 assert.equal(waitingSentence(0), "Nothing is waiting on you.");
185 assert.equal(waitingSentence(1), "1 thing is waiting on you.");
186 assert.equal(waitingSentence(8), "8 things are waiting on you.");
187});
188
189const need = (over: Partial<CodeNeed>): CodeNeed => ({
190 key: "pull:p1",
191 reason: "ready_to_merge",
192 repo,
193 ref: "#12",
194 title: "Add retries",
195 ask: "Waiting for you to merge it.",
196 by: { name: "g1t", agent: true },
197 for: "bo",
198 at: NOW - 2 * HOUR,
199 to: "/acme/web/pull/12",
200 facts: [{ label: "Files changed", value: "4", tone: null }],
201 ...over,
202});
203
204test("Code's needs become rows with what is at stake", () => {
205 const ready = codeRow(need({}));
206 assert.equal(ready.kind, "ready");
207 assert.equal(ready.stake?.text, "4 files to land");
208 assert.equal(ready.action.label, "Merge");
209 const deploy = codeRow(need({ key: "deploy:site", reason: "blocking", facts: [{ label: "Production", value: "Serving the build before", tone: "good" }] }));
210 assert.equal(deploy.kind, "deploy");
211 assert.equal(deploy.stake?.text, "Production on an older build");
212 assert.equal(codeRow(need({ reason: "checks_failing" })).kind, "pull_blocked");
213 assert.equal(codeRow(need({ key: "run:r1", reason: "stalled", facts: [{ label: "Cost so far", value: "$1.20", tone: null }] })).stake?.text, "$1.20 so far");
214});
215
216const row = (over: Partial<AttentionRow>): AttentionRow => ({
217 key: "k",
218 kind: "chat",
219 title: "t",
220 detail: "d",
221 stake: null,
222 action: { label: "Open", to: "/x" },
223 owner: null,
224 at: NOW,
225 from: "chat",
226 ...over,
227});
228
229test("Start here: the most pressing tier first, then what has waited longest", () => {
230 const rows = [
231 row({ key: "chat:old", kind: "chat", at: NOW - 5 * DAY, action: { label: "Reply", to: "/acme/-/chat/general" } }),
232 row({ key: "ready:new", kind: "ready", at: NOW - HOUR, action: { label: "Merge", to: "/acme/web/pull/2" } }),
233 row({ key: "ready:old", kind: "ready", at: NOW - 3 * HOUR, action: { label: "Merge", to: "/acme/web/pull/1" } }),
234 row({ key: "session:s", kind: "session_cap", at: NOW - 10 * 60_000, action: { label: "Approve more", to: "/acme/-/agents/margo/sessions/s" } }),
235 ];
236 const ranked = rankAttention(rows);
237 assert.deepEqual(ranked.map((r) => r.key), ["session:s", "ready:old", "ready:new", "chat:old"]);
238 const start = startHere(ranked);
239 assert.equal(start?.row.key, "session:s");
240 assert.match(start?.why ?? "", /spend cap/);
241 // A failed production deploy beats everything.
242 const withDeploy = rankAttention([...rows, row({ key: "deploy:site", kind: "deploy", at: NOW, action: { label: "See the build", to: "/acme/site/deployments/1" } })]);
243 assert.equal(startHere(withDeploy)?.row.key, "deploy:site");
244 // Ties in tier say so.
245 const two = startHere(rankAttention(rows.filter((r) => r.kind === "ready")));
246 assert.equal(two?.row.key, "ready:old");
247 assert.match(two?.why ?? "", /Of the 2 like it, it has waited longest/);
248 assert.equal(startHere([]), null);
249});
250
251test("the same order whatever order the rows came in", () => {
252 const rows = [row({ key: "b", kind: "review", at: NOW }), row({ key: "a", kind: "review", at: NOW, action: { label: "Review", to: "/y" } })];
253 assert.deepEqual(rankAttention(rows).map((r) => r.key), ["a", "b"]);
254 assert.deepEqual(rankAttention([...rows].reverse()).map((r) => r.key), ["a", "b"]);
255});
256
257const item = (over: Partial<InboxItem>): InboxItem => ({
258 id: "n1",
259 reason: "ci_activity",
260 severity: "error",
261 title: "Checks failed on #12",
262 body: "Add retries",
263 event: "check.failed",
264 repo: "acme/web",
265 workspace: "acme",
266 subject: "pull",
267 number: 12,
268 url: "/acme/web/pull/12",
269 actor: "g1t",
270 count: 1,
271 createdAt: iso(NOW - HOUR),
272 updatedAt: iso(NOW - HOUR),
273 readAt: null,
274 doneAt: null,
275 saved: false,
276 snoozedUntil: null,
277 ...over,
278});
279
280test("notifications: warnings and failures in this workspace; none about repositories without Code", () => {
281 assert.equal(notificationRow(item({}), "acme", true)?.kind, "notification");
282 assert.equal(notificationRow(item({}), "acme", false), null);
283 assert.equal(notificationRow(item({ repo: null, url: "/acme/-/agents/margo" }), "acme", false)?.kind, "notification");
284 assert.equal(notificationRow(item({ severity: "info" }), "acme", true), null);
285 assert.equal(notificationRow(item({ workspace: "other", repo: "other/web" }), "acme", true), null);
286 assert.equal(notificationRow(item({ readAt: iso(NOW) }), "acme", true), null);
287});
288
289test("a notification about something already listed is left out", () => {
290 const out = attention({
291 slug: "acme",
292 code: true,
293 codeNeeds: [need({})],
294 capped: [],
295 agents: [],
296 canManage: false,
297 notifications: [item({})],
298 chat: [],
299 });
300 assert.deepEqual(out.rows.map((r) => r.key), ["pull:p1"]);
301 assert.deepEqual(out.missing, []);
302});
303
304test("without Code access no Code row is asked for or shown, and a silent source is named", () => {
305 const out = attention({
306 slug: "acme",
307 code: false,
308 codeNeeds: [need({})],
309 capped: null,
310 agents: null,
311 canManage: false,
312 notifications: [item({}), item({ id: "n2", repo: null, reason: "agent", severity: "warning", url: "/acme/-/agents/margo" })],
313 chat: null,
314 });
315 assert.deepEqual(out.rows.map((r) => r.key), ["notification:n2"]);
316 assert.equal(out.rows.some((r) => r.from === "code"), false);
317 assert.deepEqual(out.missing, ["Agents", "Chat"]);
318});
319
320test("an agent out of budget is listed only for those who may raise it", () => {
321 const agent = { id: "a1", handle: "margo", display_name: "Margo", status: "out_of_budget", spent_month_micros: 52_000_000, budget: { monthly_micros: 50_000_000 }, updated_at: iso(NOW) };
322 assert.equal(agentRow(agent, "acme")?.stake?.text, "$0.00 left");
323 const base = { slug: "acme", code: true, codeNeeds: [], capped: [], notifications: [], chat: [] };
324 assert.equal(attention({ ...base, agents: [agent], canManage: false }).rows.length, 0);
325 assert.equal(attention({ ...base, agents: [agent], canManage: true }).rows[0]?.kind, "agent_budget");
326});
327
328test("chat: mentions anywhere and unread direct messages, never muted", () => {
329 const channel = { id: "c1", kind: "channel" as const, name: "general", last_message_at: iso(NOW) };
330 assert.equal(chatRow({ channel, title: "general", muted: false, unread: 4, mentions: 0 }, "acme"), null);
331 assert.equal(chatRow({ channel, title: "general", muted: false, unread: 4, mentions: 2 }, "acme")?.stake?.text, "2 mentions");
332 assert.equal(chatRow({ channel, title: "general", muted: true, unread: 4, mentions: 2 }, "acme"), null);
333 const dm = chatRow({ channel: { ...channel, kind: "dm", name: null }, title: "Bo Reed", muted: false, unread: 1, mentions: 0 }, "acme");
334 assert.equal(dm?.action.to, "/acme/-/chat/dm/c1");
335});
336
337test("spent today: today's UTC group of the statement, at price, without money in", () => {
338 const spend = spendToday(
339 {
340 groups: [
341 {
342 key: "2026-10-09",
343 label: "2026-10-09",
344 chargedMicros: 0,
345 lines: [
346 { kind: "Agent runs", count: 12, chargedMicros: 3_000_000, costMicros: 2_500_000, priceMicros: 4_000_000 },
347 { kind: "Sandbox time", count: 12, chargedMicros: 600_000, costMicros: 500_000 },
348 { kind: "Payments", count: 1, chargedMicros: -50_000_000, costMicros: 0, priceMicros: 0 },
349 ],
350 },
351 { key: "2026-10-08", label: "2026-10-08", chargedMicros: 0, lines: [{ kind: "Agent runs", count: 3, chargedMicros: 9_000_000, costMicros: 0 }] },
352 ],
353 totals: { chargedMicros: 12_600_000, paidMicros: 50_000_000, costMicros: 0, entries: 4, priceMicros: 13_600_000 },
354 },
355 NOW,
356 );
357 assert.equal(spend.day, "2026-10-09");
358 assert.equal(spend.totalMicros, 4_600_000);
359 assert.deepEqual(spend.lines.map((l) => l.kind), ["Agent runs", "Sandbox time"]);
360 assert.equal(spend.monthMicros, 13_600_000);
361});