1const assert = require("node:assert/strict");
2const test = require("node:test");
3
4const {
5 renderComment,
6 resolve,
7 upsertCommentForCurrentHead,
8 validateResult,
9} = require("./thread-transfer-report.cjs");
10
11function result(overrides = {}) {
12 const observed = {
13 totalWireBytes: 2_200_000,
14 threadSnapshotWireBytes: 1_950_000,
15 threadSnapshotDecodedBytes: 9_100_000,
16 measuredTurnWebSocketWireBytes: 250_000,
17 measuredTurnWebSocketDecodedBytes: 1_150_000,
18 measuredTurnWebSocketMessages: 15,
19 };
20 const ceiling = {
21 totalWireBytes: 2_900_000,
22 threadSnapshotWireBytes: 2_600_000,
23 measuredTurnWebSocketWireBytes: 320_000,
24 measuredTurnWebSocketDecodedBytes: 1_550_000,
25 measuredTurnWebSocketMessages: 20,
26 };
27 return {
28 schemaVersion: 1,
29 scenario: {
30 id: "thread-transfer-v1",
31 historyTurns: 10,
32 historyCommandToolsPerTurn: 5,
33 historyMcpResultBytes: 900_000,
34 measuredCommandTools: 20,
35 measuredMcpResultBytes: 1_100_000,
36 },
37 providers: {
38 codex: { observed: { ...observed, ...overrides }, ceiling },
39 claudeAgent: { observed, ceiling },
40 },
41 };
42}
43
44test("validates the fixed artifact schema", () => {
45 assert.equal(validateResult(result()).schemaVersion, 1);
46 assert.throws(
47 () => validateResult({ ...result(), injectedMarkdown: "@everyone" }),
48 /unexpected fields/,
49 );
50 assert.throws(
51 () => validateResult(result({ totalWireBytes: "lots" })),
52 /non-negative safe integer/,
53 );
54});
55
56test("renders baseline, impact, ceiling, and ceiling changes", () => {
57 const baseline = result();
58 const current = result({ measuredTurnWebSocketWireBytes: 260_000 });
59 current.providers.codex.ceiling = {
60 ...current.providers.codex.ceiling,
61 measuredTurnWebSocketWireBytes: 330_000,
62 };
63 const comment = renderComment({
64 current,
65 baseline,
66 currentRun: {
67 sha: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
68 conclusion: "success",
69 url: "https://github.com/pingdotgg/t3code/actions/runs/2",
70 },
71 baselineRun: {
72 sha: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
73 matchesBase: true,
74 url: "https://github.com/pingdotgg/t3code/actions/runs/1",
75 },
76 });
77
78 assert.match(comment, /Main baseline \| This PR \| Impact \| PR ceiling/);
79 assert.match(comment, /\+9\.8 KiB \(\+4\.0%\)/);
80 assert.match(comment, /This PR changes transfer ceilings/);
81 assert.match(comment, /312\.5 KiB → 322\.3 KiB/);
82 assert.match(comment, /<!-- t3-thread-transfer-report -->/);
83 assert.match(
84 comment,
85 /<!-- t3-thread-transfer-result-sha:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -->/,
86 );
87});
88
89test("resolves a fallback PR with a redacted head repo and exact main baseline", async () => {
90 const outputs = {};
91 const listWorkflowRunArtifacts = () => {};
92 const listWorkflowRuns = () => {};
93 const listPullRequestsAssociatedWithCommit = () => {};
94 const github = {
95 paginate: async (method, input) => {
96 if (method === listPullRequestsAssociatedWithCommit) {
97 return [
98 {
99 number: 5350,
100 state: "open",
101 head: { sha: "head-sha", ref: "feature-branch", repo: null },
102 },
103 ];
104 }
105 if (method === listWorkflowRunArtifacts) {
106 return [
107 {
108 name: "thread-transfer-results",
109 expired: false,
110 runId: input.run_id,
111 },
112 ];
113 }
114 if (method === listWorkflowRuns) {
115 return [{ id: 1, head_sha: "base-sha" }];
116 }
117 throw new Error("unexpected pagination call");
118 },
119 rest: {
120 actions: { listWorkflowRunArtifacts, listWorkflowRuns },
121 pulls: {
122 get: async () => ({
123 data: {
124 head: { sha: "head-sha" },
125 base: { sha: "base-sha", ref: "main" },
126 },
127 }),
128 },
129 repos: { listPullRequestsAssociatedWithCommit },
130 },
131 };
132 await resolve({
133 github,
134 context: {
135 repo: { owner: "pingdotgg", repo: "t3code" },
136 payload: {
137 workflow_run: {
138 id: 2,
139 event: "pull_request",
140 workflow_id: 3,
141 head_sha: "head-sha",
142 head_branch: "feature-branch",
143 head_repository: { full_name: "pingdotgg/t3code" },
144 conclusion: "success",
145 pull_requests: [],
146 },
147 },
148 },
149 core: {
150 info: () => {},
151 setOutput: (key, value) => {
152 outputs[key] = value;
153 },
154 },
155 });
156
157 assert.equal(outputs.publish, "true");
158 assert.equal(outputs.pull_number, "5350");
159 assert.equal(outputs.pr_artifact, "true");
160 assert.equal(outputs.baseline_run_id, "1");
161 assert.equal(outputs.baseline_matches_base, "true");
162});
163
164test("does not guess when a fallback commit belongs to multiple PRs", async () => {
165 const outputs = {};
166 const listPullRequestsAssociatedWithCommit = () => {};
167 let fetchedPull = false;
168 await resolve({
169 github: {
170 paginate: async (method) => {
171 assert.equal(method, listPullRequestsAssociatedWithCommit);
172 return [5350, 5351].map((number) => ({
173 number,
174 state: "open",
175 head: {
176 sha: "head-sha",
177 ref: "feature-branch",
178 repo: { full_name: "pingdotgg/t3code" },
179 },
180 }));
181 },
182 rest: {
183 actions: {},
184 pulls: {
185 get: async () => {
186 fetchedPull = true;
187 },
188 },
189 repos: { listPullRequestsAssociatedWithCommit },
190 },
191 },
192 context: {
193 repo: { owner: "pingdotgg", repo: "t3code" },
194 payload: {
195 workflow_run: {
196 id: 2,
197 event: "pull_request",
198 workflow_id: 3,
199 head_sha: "head-sha",
200 head_branch: "feature-branch",
201 head_repository: { full_name: "pingdotgg/t3code" },
202 conclusion: "success",
203 pull_requests: [],
204 },
205 },
206 },
207 core: {
208 info: () => {},
209 setOutput: (key, value) => {
210 outputs[key] = value;
211 },
212 },
213 });
214
215 assert.equal(outputs.publish, "false");
216 assert.equal(fetchedPull, false);
217});
218
219test("does not publish a stale result after the PR head advances", async () => {
220 let listedComments = false;
221 const info = [];
222 const published = await upsertCommentForCurrentHead(
223 {
224 paginate: async () => {
225 listedComments = true;
226 return [];
227 },
228 rest: {
229 issues: {
230 listComments: () => {},
231 createComment: () => {
232 throw new Error("must not create a stale comment");
233 },
234 updateComment: () => {
235 throw new Error("must not update a stale comment");
236 },
237 },
238 pulls: {
239 get: async () => ({ data: { head: { sha: "new-head-sha" } } }),
240 },
241 },
242 },
243 { repo: { owner: "pingdotgg", repo: "t3code" } },
244 { info: (message) => info.push(message) },
245 5350,
246 "old-head-sha",
247 "stale body",
248 );
249
250 assert.equal(published, false);
251 assert.equal(listedComments, false);
252 assert.deepEqual(info, ["Skipping stale CI result old-head-sha; PR head is new-head-sha."]);
253});
254
255test("preserves a successful result when a same-SHA rerun has no artifact", async () => {
256 let updatedComment = false;
257 const sha = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
258 const published = await upsertCommentForCurrentHead(
259 {
260 paginate: async () => [
261 {
262 id: 1,
263 user: { login: "github-actions[bot]" },
264 body: `<!-- t3-thread-transfer-report -->\n<!-- t3-thread-transfer-result-sha:${sha} -->`,
265 },
266 ],
267 rest: {
268 issues: {
269 listComments: () => {},
270 createComment: () => {
271 updatedComment = true;
272 },
273 updateComment: () => {
274 updatedComment = true;
275 },
276 },
277 pulls: {
278 get: async () => ({ data: { head: { sha } } }),
279 },
280 },
281 },
282 { repo: { owner: "pingdotgg", repo: "t3code" } },
283 { info: () => {} },
284 5350,
285 sha,
286 "missing artifact warning",
287 { preserveResultSha: sha },
288 );
289
290 assert.equal(published, true);
291 assert.equal(updatedComment, false);
292});
293
294test("accepts V2 without comparing it to the V1 scenario", () => {
295 const current = result();
296 current.scenario.id = "thread-transfer-v2";
297 current.providers.codex.ceiling = { ...current.providers.codex.ceiling, totalWireBytes: 3000000 };
298 assert.equal(validateResult(current), current);
299 const comment = renderComment({
300 current,
301 baseline: result(),
302 currentRun: { sha: "bbbbbbbb", conclusion: "success", url: "https://example.com/current" },
303 baselineRun: { sha: "aaaaaaaa", matchesBase: true, url: "https://example.com/baseline" },
304 });
305 assert.match(comment, /fixture changed/);
306 assert.doesNotMatch(comment, /This PR changes transfer ceilings/);
307 assert.doesNotMatch(comment, /[+-]\d+\.\d+%/);
308 current.scenario.id = "unrecognized";
309 assert.throws(() => validateResult(current), /not supported/);
310});