flagon-io/g1t

public

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

g1t/apps/web/app/lib/catch-up.test.ts

68 lines2,651 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { AgentRun } from "@g1t/contracts";
5
6import { CATCH_UP_TIMEOUT_MS, catchUpPhase, catchUpRun, catchUpTitle, catchUpWhy } from "./catch-up.ts";
7
8const START = Date.parse("2026-10-05T12:00:00Z");
9
10function run(kind: AgentRun["kind"], status: AgentRun["status"], createdAt: string): AgentRun {
11 return {
12 id: `run-${kind}-${createdAt}`,
13 repo: { namespace: "acme", name: "app" },
14 number: 7,
15 title: null,
16 kind,
17 agent: "g1t-agent",
18 model: null,
19 status,
20 step: null,
21 steps: [],
22 stepCount: 0,
23 startedBy: "octo",
24 error: null,
25 costUsd: null,
26 turns: null,
27 createdAt,
28 startedAt: null,
29 finishedAt: null,
30 updatedAt: createdAt,
31 };
32}
33
34test("the update run for a request is the newest one since it was made", () => {
35 const runs = [
36 run("update", "failed", "2026-10-05T11:00:00Z"),
37 run("review", "running", "2026-10-05T12:00:05Z"),
38 run("update", "running", "2026-10-05T12:00:03Z"),
39 ];
40 assert.equal(catchUpRun(runs, START)?.createdAt, "2026-10-05T12:00:03Z");
41 assert.equal(catchUpRun(runs.slice(0, 2), START), null);
42});
43
44test("it is done as soon as the pull request is no longer behind", () => {
45 assert.equal(catchUpPhase({ behind: false, run: null, startedAt: START, now: START + 1000 }), "done");
46 const failed = run("update", "failed", "2026-10-05T12:00:03Z");
47 assert.equal(catchUpPhase({ behind: false, run: failed, startedAt: START, now: START }), "done");
48});
49
50test("a run that ended while still behind failed", () => {
51 for (const status of ["failed", "stopped"] as const) {
52 const ended = run("update", status, "2026-10-05T12:00:03Z");
53 assert.equal(catchUpPhase({ behind: true, run: ended, startedAt: START, now: START + 60_000 }), "failed");
54 }
55});
56
57test("it never waits forever", () => {
58 const going = run("update", "running", "2026-10-05T12:00:03Z");
59 assert.equal(catchUpPhase({ behind: true, run: going, startedAt: START, now: START + 60_000 }), "working");
60 assert.equal(catchUpPhase({ behind: true, run: null, startedAt: START, now: START + CATCH_UP_TIMEOUT_MS + 1 }), "timed_out");
61});
62
63test("the box says who is doing what", () => {
64 assert.equal(catchUpTitle("conflicting", "main"), "g1t-agent is resolving conflicts with main");
65 assert.equal(catchUpTitle("overlap", "main"), "g1t-agent is merging main into this pull request");
66 assert.match(catchUpWhy({ reason: "overlap", paths: ["a.rs"] }, "main"), /both changed one file/);
67 assert.match(catchUpWhy({ reason: "conflicting", paths: ["a.rs", "b.rs"] }, "main"), /conflicts in 2 files/);
68});