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

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Catching up with main takes seconds when the two sides touched different files1import 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});