Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

92 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { type BoardItem, type BoardSession, boardOf, peopleOn, stageOf } from "./board.ts";
5
6const NOW = Date.parse("2026-10-17T12:00:00Z");
7const DAY = 86_400_000;
8
9function item(number: number, change: Partial<BoardItem> = {}): BoardItem {
10 return { number, state: "open", assignees: [], repos: [], closed_at: null, ...change };
11}
12
13function target(path: string, landed: boolean) {
14 return { repo_id: path, path, role: "target" as const, legacy_number: null, landed };
15}
16
17function session(change: Partial<BoardSession>): BoardSession {
18 return { item: null, state: "active", actor: "ada", harness: "claude_code", pull: null, pull_status: null, ...change };
19}
20
21const none = { pulls: [], sessions: [], now: NOW };
22
23test("an open item nobody is on is in the backlog", () => {
24 assert.equal(stageOf(item(1), none), "backlog");
25 // A session that ended, or one on another item, puts nobody on it.
26 assert.equal(stageOf(item(1), { ...none, sessions: [session({ item: 1, state: "ended" }), session({ item: 2 })] }), "backlog");
27 // So does a pull request that merged or closed.
28 assert.equal(stageOf(item(1), { ...none, pulls: [{ item: 1, status: "closed" }] }), "backlog");
29});
30
31test("an item someone is on, or with a draft, is in progress", () => {
32 assert.equal(stageOf(item(1, { assignees: ["ada"] }), none), "in_progress");
33 assert.equal(stageOf(item(1, { claimed: true }), none), "in_progress");
34 assert.equal(stageOf(item(1), { ...none, sessions: [session({ item: 1 })] }), "in_progress");
35 assert.equal(stageOf(item(1), { ...none, sessions: [session({ item: 1, state: "idle" })] }), "in_progress");
36 assert.equal(stageOf(item(1), { ...none, pulls: [{ item: 1, status: "draft" }] }), "in_progress");
37});
38
39test("an item with an open pull request is in review, even with someone on it", () => {
40 assert.equal(stageOf(item(1, { assignees: ["ada"] }), { ...none, pulls: [{ item: 1, status: "open" }] }), "in_review");
41 // A session names its pull request's status too.
42 assert.equal(stageOf(item(1), { ...none, sessions: [session({ item: 1, pull: 4, pull_status: "open" })] }), "in_review");
43 assert.equal(stageOf(item(1), { ...none, pulls: [{ item: 2, status: "open" }] }), "backlog");
44});
45
46test("an item landed in some targets but not all is landing, ahead of review", () => {
47 const repos = [target("acme/web", true), target("acme/api", false)];
48 assert.equal(stageOf(item(1, { repos }), { ...none, pulls: [{ item: 1, status: "open" }] }), "landing");
49 // Landed in none of them is not landing.
50 assert.equal(stageOf(item(1, { repos: [target("acme/web", false), target("acme/api", false)] }), none), "backlog");
51 // Where it only touched does not count.
52 const touched = { ...target("acme/docs", true), role: "touched" as const };
53 assert.equal(stageOf(item(1, { repos: [touched, target("acme/api", false)] }), none), "backlog");
54});
55
56test("an item closed in the last two weeks is done, and older ones are left out", () => {
57 assert.equal(stageOf(item(1, { state: "closed", closed_at: new Date(NOW - 3 * DAY).toISOString() }), none), "done");
58 assert.equal(stageOf(item(1, { state: "closed", closed_at: new Date(NOW - 15 * DAY).toISOString() }), none), null);
59 assert.equal(stageOf(item(1, { state: "closed", closed_at: null }), none), null);
60 // Done wins over everything else.
61 const repos = [target("acme/web", true), target("acme/api", false)];
62 assert.equal(stageOf(item(1, { state: "closed", repos, closed_at: new Date(NOW - DAY).toISOString() }), { ...none, pulls: [{ item: 1, status: "open" }] }), "done");
63});
64
65test("the board puts each item in its stage once, done newest first", () => {
66 const items = [
67 item(1),
68 item(2, { assignees: ["ada"] }),
69 item(3, { state: "closed", closed_at: new Date(NOW - 5 * DAY).toISOString() }),
70 item(4, { state: "closed", closed_at: new Date(NOW - DAY).toISOString() }),
71 item(5, { state: "closed", closed_at: new Date(NOW - 30 * DAY).toISOString() }),
72 item(1),
73 ];
74 const board = boardOf(items, none);
75 assert.deepEqual(board.backlog.map((card) => card.item.number), [1]);
76 assert.deepEqual(board.in_progress.map((card) => card.item.number), [2]);
77 assert.deepEqual(board.done.map((card) => card.item.number), [4, 3]);
78 assert.deepEqual([...board.in_review, ...board.landing], []);
79});
80
81test("who is on an item: its assignees, then who runs a live session on it, in what", () => {
82 const sessions = [
83 session({ item: 1, actor: "ada", harness: "claude_code" }),
84 session({ item: 1, actor: "bob", harness: "codex" }),
85 session({ item: 1, actor: "cy", state: "ended" }),
86 session({ item: 2, actor: "dee" }),
87 ];
88 assert.deepEqual(peopleOn(item(1, { assignees: ["ada"] }), sessions), [
89 { name: "ada", harness: "claude_code" },
90 { name: "bob", harness: "codex" },
91 ]);
92});