Fork Horse repository, listed by its owner. Publisher snapshot.
packages/forkhorse-dashboard/test/usage.test.ts
Snapshot at 34e3175
1import { installDom } from "./dom.ts";
2import { createRequire } from "node:module";
3import assert from "node:assert/strict";
4import { test } from "node:test";
5import { createElement } from "react";
6import { renderToStaticMarkup } from "react-dom/server";
7import { TooltipProvider } from "@cloudflare/kumo";
8import { ownerNeeds } from "../src/needs-you-model.ts";
9import { mountDashboard } from "../src/dashboard.ts";
10import { createHttpTransport } from "../src/transport.ts";
11import { reviewGate, stateView } from "../src/model.ts";
12import {
13 agentUsageToday,
14 laneUsage,
15 tokenNumber,
16 totalTokens,
17 usageTooltip,
18} from "../src/usage.ts";
19import { BudgetUsage, UsageFigures } from "../src/usage.tsx";
20import type { StateResponse } from "../src/contracts.ts";
21import { usageFixtureState, usageFixtureDetail } from "./usage-fixtures.ts";
22const brand = { name: "Fixture product", tagline: "Fixture" };
23const { JSDOM } = createRequire(import.meta.url)("jsdom");
24const now = Date.parse("2026-10-13T16:00:00Z");
25const fixture = (id = "usage-race") => stateView(usageFixtureState(id, now));
26async function until(fn: () => unknown) {
27 for (let i = 0; i < 300; i++) {
28 if (fn()) return;
29 await new Promise((r) => setTimeout(r, 5));
30 }
31 assert.fail("Usage DOM did not settle");
32}
33function setup(scenario = "usage-race", route = "#race/FH-040", owner = true, noDetail = false, amend?: (wire: StateResponse) => void) {
34 const dom = new JSDOM('<div id="dashboard"></div>', {
35 url: `https://fixture.idiot.tax/${route}`,
36 });
37 installDom(dom.window);
38 const root = dom.window.document.getElementById("dashboard")! as HTMLElement;
39 const wire = usageFixtureState(scenario);
40 amend?.(wire);
41 const calls: { url: URL; method: string }[] = [];
42 const transport = createHttpTransport({
43 origin: "https://fixture.idiot.tax",
44 fetch: async (input, init) => {
45 const url = new URL(String(input));
46 calls.push({ url, method: init?.method ?? "GET" });
47 if (url.pathname.endsWith("/state")) return Response.json(wire);
48 if (url.pathname.endsWith("/activity")) return Response.json({ activity: [], nextAfter: 0 });
49 return Response.json(
50 usageFixtureDetail(wire, decodeURIComponent(url.pathname.split("/").at(-1)!)),
51 );
52 },
53 });
54 if (noDetail) delete transport.getReview;
55 const app = mountDashboard(root, {
56 brand,
57 fixture: true,
58 owner,
59 agent: "fixture-agent",
60 initialProject: scenario,
61 projects: [{ id: scenario, label: "Usage fixture" }],
62 transport,
63 });
64 return {
65 dom,
66 root,
67 wire,
68 calls,
69 close() {
70 app.dispose();
71 dom.window.close();
72 },
73 };
74}
75test("token formatting stays exact under 100k; sources, model and missing reports stay explicit", () => {
76 assert.deepEqual([0, 18400, 99999, 100000, 340000, 1200000].map(tokenNumber), [
77 "0",
78 "18,400",
79 "99,999",
80 "100k",
81 "340k",
82 "1.2M",
83 ]);
84 const state = fixture("usage-both");
85 const usage = state.reviews[0].usageAtReview!;
86 assert.equal(
87 usageTooltip(usage.reported!, "fixture-agent", brand),
88 "Reported by fixture-agent through Fixture product. Fixture product can't verify it.",
89 );
90 assert.equal(
91 usageTooltip(usage.metered!, "fixture-agent", brand),
92 "Metered by AI Gateway for fixture-agent.",
93 );
94 const markup = renderToStaticMarkup(
95 createElement(
96 TooltipProvider,
97 null,
98 createElement(UsageFigures, { usage, agent: "fixture-agent", brand, split: true }),
99 ),
100 );
101 assert.match(markup, /reported/);
102 assert.match(markup, /metered/);
103 assert.match(markup, /fixture-model \(reported\)/);
104 assert.match(markup, /as of/);
105 assert.doesNotMatch(markup, /670k/);
106 assert.match(
107 renderToStaticMarkup(createElement(UsageFigures, { agent: "fixture-agent", brand })),
108 /Not reported/,
109 );
110});
111test("promotion follows current entrant state rather than the older review snapshot, for owner and queue", () => {
112 const state = fixture();
113 const r = state.reviews[2];
114 r.usageAtReview = state.reviews[0].usageAtReview;
115 assert.equal(reviewGate(r, state).promote, false);
116 assert.equal(
117 reviewGate(r, state).reason,
118 "Over its token budget (reported). It can't win this race.",
119 );
120 state.races![0].entrants[2].budget = "within";
121 assert.equal(reviewGate(r, state).promote, true);
122 state.races![0].entrants[2].budget = "unchecked";
123 assert.equal(reviewGate(r, state).reason, "Report usage first: this race has a token budget.");
124 state.races![0].tokenBudget = null;
125 assert.equal(reviewGate(r, state).promote, true);
126 assert.equal(
127 reviewGate(fixture("usage-legacy").reviews[0], fixture("usage-legacy")).promote,
128 true,
129 );
130});
131test("accepted collision gating remains ahead of current entrant usage gating for both roles", () => {
132 const state = fixture();
133 const review = state.reviews[2];
134 const blocker = {
135 id: "usage-collision", agent: review.agent, pushingAgent: review.agent,
136 claimingAgent: "claiming-agent", packet: "claimed-packet", pushingPacket: review.packet,
137 repoName: review.repoName, sha: review.sha, paths: ["src/shared.ts"],
138 reason: "Fixture collision", resolved: false,
139 };
140 state.blockers.push(blocker);
141 for (const owner of [true, false]) {
142 const gate = reviewGate(review, state, owner);
143 assert.equal(gate.approve, false);
144 assert.equal(gate.promote, false);
145 assert.match(gate.reason, /Blocked: this fork pushed into claimed-packet/);
146 assert.ok(gate.reason.includes(owner ? "Mark the collision resolved first." : "Waiting for the owner."));
147 }
148 blocker.resolved = true;
149 assert.equal(reviewGate(review, state).reason, "Over its token budget (reported). It can't win this race.");
150 state.races![0].entrants[2].budget = "unchecked";
151 assert.equal(reviewGate(review, state).promote, false);
152 assert.equal(reviewGate(review, state).reason, "Report usage first: this race has a token budget.");
153 state.races![0].tokenBudget = null;
154 assert.equal(reviewGate(review, state).promote, true);
155});
156test("today totals deduplicate claims, race entrants and superseded review snapshots by binding and source", () => {
157 const state = fixture("usage-both");
158 const r = state.reviews[0];
159 state.reviews.push({
160 ...r,
161 id: "older",
162 usageAtReview: {
163 reported: { ...r.usageAtReview!.reported!, inputTokens: 1000, at: "2026-10-13T08:00:00Z" },
164 metered: null,
165 },
166 });
167 let totals = agentUsageToday(state, r.agent, now);
168 assert.equal(totalTokens(totals.reported!), 420000);
169 assert.equal(totalTokens(totals.metered!), 250000);
170 const yesterday = {
171 reported: { ...r.usageAtReview!.reported!, at: "2026-10-11T16:00:00Z" },
172 metered: null,
173 };
174 state.reviews.push({
175 ...r,
176 id: "yesterday",
177 packet: "other",
178 repoName: "other",
179 usageAtReview: yesterday,
180 });
181 totals = agentUsageToday(state, r.agent, now);
182 assert.equal(totalTokens(totals.reported!), 420000);
183 assert.deepEqual(agentUsageToday(state, "unreported", now), { reported: null, metered: null });
184 state.reviews.push({
185 ...r,
186 id: "second-packet",
187 packet: "second",
188 usageAtReview: r.usageAtReview,
189 });
190 assert.equal(totalTokens(agentUsageToday(state, r.agent, now).reported!), 840000);
191});
192test("graph historical promotion uses its snapshot while the active lane uses current usage", () => {
193 const state = fixture();
194 const r = state.reviews[0];
195 const live = state.races![0].entrants[0].usage!;
196 live.reported!.inputTokens += 100;
197 assert.equal(laneUsage(state, { packet: r.packet, repoName: r.repoName, review: r }), live);
198 assert.equal(
199 laneUsage(state, { packet: r.packet, repoName: r.repoName, review: r, promoted: {} }),
200 r.usageAtReview,
201 );
202});
203test("race Compare is factual and read-only for both roles, with true ratio meters and detail-backed file counts", async () => {
204 for (const owner of [true, false]) {
205 const c = setup("usage-race", "#race/FH-040", owner);
206 try {
207 await until(
208 () =>
209 c.root.querySelector(".race-compare")?.textContent?.includes("fewest") &&
210 c.calls.filter((call) => call.url.pathname.includes("/reviews/")).length === 3,
211 );
212 const meters = [...c.root.querySelectorAll<HTMLMeterElement>(".race-track meter")];
213 assert.deepEqual(
214 meters.map((m) => [m.value, m.max]),
215 [
216 [420000, 1000000],
217 [820000, 1000000],
218 [1000000, 1000000],
219 ],
220 );
221 assert.match(c.root.textContent!, /1.1M \/ 1M tokens 路 reported/);
222 assert.match(c.root.textContent!, /Near budget/);
223 assert.match(c.root.textContent!, /Over budget/);
224 assert.match(
225 c.root.querySelector(".race-compare")!.textContent!,
226 /Time to Approved.*Time to Promoted.*Checks passed.*Files changed.*Tokens/s,
227 );
228 // This fixture begins loading at first push, after every claim.
229 assert.doesNotMatch(c.root.querySelector(".race-compare")!.textContent!, /Recorded pushes/);
230 assert.equal(c.root.querySelector('.race-results [data-label="Pushes"]'), null);
231 assert.doesNotMatch(
232 c.root.querySelector(".race-compare")!.textContent!,
233 /score|cost|rank|winner/i,
234 );
235 assert.equal(
236 c.calls.some((call) => call.method !== "GET"),
237 false,
238 );
239 } finally {
240 c.close();
241 }
242 }
243});
244test("queue Tokens column is conditional; over and unchecked hide Promote in queue and detail", async () => {
245 for (const [scenario, id, caption] of [
246 ["usage-over", "usage-review-2", "Over its token budget (reported). It can't win this race."],
247 ["usage-unchecked", "usage-review-0", "Report usage first: this race has a token budget."],
248 ]) {
249 for (const route of ["#review", `#review/${id}`]) {
250 const c = setup(scenario, route);
251 try {
252 await until(() => c.root.querySelector(".usage-promotion-caption"));
253 const scope =
254 route === "#review"
255 ? [...c.root.querySelectorAll(".review-card")].find(
256 (r) => r.querySelector(`[data-review="${id}"]`) || r.textContent!.includes(caption),
257 )!
258 : c.root.querySelector(".review-detail")!;
259 assert.ok(scope.textContent!.includes(caption));
260 assert.equal(scope.querySelector('[data-action="promote"]'), null);
261 if (route === "#review") {
262 assert.equal(scope.textContent!.split(caption).length - 1, 1);
263 assert.equal(scope.querySelectorAll(".usage-promotion-caption").length, 1);
264 assert.doesNotMatch(scope.querySelectorAll("td")[3].textContent!, /Report usage first|Over its token budget/);
265 assert.equal(scope.querySelector(".column-tokens .usage-freshness"), null);
266 }
267 if (route !== "#review") {
268 assert.match(scope.textContent!, /Usage.*Tokens to this review/s);
269 assert.equal(scope.querySelectorAll(".review-milestone").length, 3);
270 }
271 assert.equal(
272 c.calls.some((call) => call.method !== "GET"),
273 false,
274 );
275 } finally {
276 c.close();
277 }
278 }
279 }
280 const c = setup("usage-legacy", "#review");
281 try {
282 await until(() => c.root.querySelector(".review-card"));
283 assert.equal(!!c.root.querySelector(".table-review .column-tokens"), false);
284 } finally {
285 c.close();
286 }
287});
288test("both sources stay separate in race budget and agent totals; unchecked and missing detail are explicit", async () => {
289 const c = setup("usage-both", "#agents");
290 try {
291 await until(() => c.root.querySelector(".table-agents"));
292 const row = c.root.querySelector(".table-agents tbody tr")!;
293 assert.match(row.textContent!, /420k tokens 路 reported/);
294 assert.match(row.textContent!, /250k tokens 路 metered/);
295 assert.doesNotMatch(row.textContent!, /670k/);
296 assert.match(c.root.textContent!, /do not measure tokens consumed today/);
297 } finally {
298 c.close();
299 }
300 const u = setup("usage-unchecked", "#race/FH-040", false, true);
301 try {
302 await until(() => u.root.querySelector(".race-compare"));
303 assert.match(u.root.textContent!, /Budget unchecked/);
304 assert.match(u.root.textContent!, /Not reported/);
305 assert.match(u.root.textContent!, /Unavailable/);
306 } finally {
307 u.close();
308 }
309});
310test("Compare distinguishes an entrant without a review from a host without review detail", async () => {
311 for (const [scenario, noDetail, expected] of [
312 ["usage-no-review", false, ["4", "4", "No review yet"]],
313 ["usage-race", true, ["Unavailable", "Unavailable", "Unavailable"]],
314 ] as const) {
315 const c = setup(scenario, "#race/FH-040", true, noDetail);
316 try {
317 await until(() => {
318 const row = [...c.root.querySelectorAll(".race-compare tbody tr")]
319 .find((r) => r.querySelector("th")?.textContent === "Files changed");
320 return row && [...row.querySelectorAll(".compare-value")]
321 .every((cell, i) => cell.textContent === expected[i]);
322 });
323 const row = [...c.root.querySelectorAll(".race-compare tbody tr")]
324 .find((r) => r.querySelector("th")?.textContent === "Files changed")!;
325 assert.deepEqual([...row.querySelectorAll(".compare-value")].map((cell) => cell.textContent), expected);
326 assert.equal(c.calls.filter((call) => call.url.pathname.includes("/reviews/")).length, noDetail ? 0 : 2);
327 assert.equal(c.calls.some((call) => call.method !== "GET"), false);
328 } finally {
329 c.close();
330 }
331 }
332});
333test("fork graph keeps tokens in tooltip and table, without figures on lane labels", async () => {
334 const c = setup("usage-race", "#overview");
335 try {
336 await until(() => c.root.querySelector(".fork-lane-label"));
337 const label = c.root.querySelector(".fork-lane-label")!;
338 assert.doesNotMatch(label.textContent!, /tokens|reported/);
339 assert.match(label.getAttribute("title")!, /^Tokens: 420k 路 reported 路 as of/);
340 assert.match(label.getAttribute("title")!, /can't verify it/);
341 assert.match(
342 c.root.querySelector(".fork-table-wrap")?.textContent ??
343 c.root.querySelector(".fork-card")!.textContent!,
344 /Tokens/,
345 );
346 assert.match(c.root.querySelector(".fork-card")!.textContent!, /420k reported/);
347 const table = c.root.querySelector<HTMLElement>(".fork-table")!;
348 assert.equal(table.querySelector(".usage-figure")!.getAttribute("tabindex"), "-1");
349 assert.match(table.querySelector(".usage-figure")!.getAttribute("aria-label")!, /420,000 tokens: 400,000 in 路 20,000 out 路 reported 路 fixture-model \(reported\) 路 as of/);
350 assert.equal(table.style.clipPath, "inset(50%)");
351 assert.ok([...table.querySelectorAll("button")].every((button) => button.tabIndex === -1));
352 c.root.querySelector<HTMLButtonElement>(".fork-disclosure")!.click();
353 await until(() => table.style.clipPath === "");
354 assert.ok([...table.querySelectorAll("button")].every((button) => button.tabIndex === 0));
355 assert.match(table.textContent!, /420k reported/);
356 assert.equal(table.querySelector(".usage-figure")!.getAttribute("tabindex"), "0");
357 } finally {
358 c.close();
359 }
360});
361
362test("budget boundary labels come from core and the gauge selects metered before reported", () => {
363 const usage = fixture().races![0].entrants[0].usage!;
364 for (const [total, status, label] of [
365 [0, "within", "Within budget"],
366 [799999, "within", "Within budget"],
367 [800000, "near", "Near budget"],
368 [1000000, "near", "Near budget"],
369 [1000001, "over", "Over budget"],
370 ] as const) {
371 usage.reported!.inputTokens = total;
372 usage.reported!.outputTokens = 0;
373 const html = renderToStaticMarkup(
374 createElement(
375 TooltipProvider,
376 null,
377 createElement(BudgetUsage, {
378 usage,
379 budget: 1000000,
380 status,
381 agent: "fixture-agent",
382 brand,
383 }),
384 ),
385 );
386 assert.ok(html.includes(label));
387 assert.ok(html.includes(`value="${total}"`));
388 assert.ok(html.includes(`${total.toLocaleString("en-US")} of 1,000,000 tokens (reported)`));
389 }
390 usage.metered = {
391 inputTokens: 25000,
392 outputTokens: 0,
393 at: usage.reported!.at,
394 source: "metered",
395 };
396 const html = renderToStaticMarkup(
397 createElement(
398 TooltipProvider,
399 null,
400 createElement(BudgetUsage, {
401 usage,
402 budget: 1000000,
403 status: "within",
404 agent: "fixture-agent",
405 brand,
406 }),
407 ),
408 );
409 assert.match(html, /value="25000"/);
410 assert.match(html, /25,000 \/ 1M tokens 路 metered/);
411 assert.match(html, /1M \/ 1M tokens 路 reported/s);
412});
413test("automatic budget rejection creates no new Needs you item and removes the existing Promote need", () => {
414 const state = fixture("usage-unchecked");
415 const items = ownerNeeds(state, brand, now);
416 assert.deepEqual(
417 items.filter((item) => item.kind === "promote").map((item) => item.id),
418 ["promote:usage-review-1"],
419 );
420 assert.equal(
421 items.some((item) => /budget|usage/.test(item.kind)),
422 false,
423 );
424});
425
426test("agent review detail explains automatic rejection without owner controls", async () => {
427 const c = setup("usage-over", "#review/usage-review-2", false);
428 try {
429 await until(() => c.root.querySelector(".review-detail .usage-promotion-caption"));
430 assert.match(
431 c.root.querySelector(".review-detail")!.textContent!,
432 /Over its token budget \(reported\). It can't win this race\./,
433 );
434 assert.equal(!!c.root.querySelector(".review-detail [data-action]"), false);
435 assert.equal(
436 c.calls.some((call) => call.method !== "GET"),
437 false,
438 );
439 } finally {
440 c.close();
441 }
442});
443
444test("core unchecked state on an unbudgeted race shows Not reported and keeps Promote", async () => {
445 const race = setup("usage-unbudgeted", "#race/FH-040");
446 try {
447 await until(() => !!race.root.querySelector(".race-track"));
448 assert.equal(!!race.root.querySelector(".race-track meter"), false);
449 assert.equal(
450 race.root.querySelector(".race-track")!.textContent!.includes("Budget unchecked"),
451 false,
452 );
453 assert.match(race.root.querySelector(".race-track")!.textContent!, /Not reported/);
454 } finally {
455 race.close();
456 }
457 const review = setup("usage-unbudgeted", "#review/usage-review-0");
458 try {
459 await until(() => !!review.root.querySelector('.review-detail [data-action="promote"]'));
460 assert.equal(!!review.root.querySelector(".review-detail .usage-promotion-caption"), false);
461 assert.equal(
462 review.calls.some((call) => call.method !== "GET"),
463 false,
464 );
465 } finally {
466 review.close();
467 }
468});
469test("track, Compare, and results share accepted claim order with Tokens before Result", async () => {
470 const c = setup("usage-reordered", "#race/FH-040");
471 try {
472 await until(() => !!c.root.querySelector(".race-compare"));
473 const track = c.root.querySelector(".race-track")!;
474 const ordered = ["fixture-agent", "fixture-peer", "fixture-third"];
475 assert.deepEqual(
476 [...track.querySelectorAll("tbody tr")].map((row) => row.getAttribute("data-race-agent")),
477 ordered,
478 );
479 assert.deepEqual(
480 [...c.root.querySelectorAll(".race-compare thead th")].slice(1).map((th) => th.textContent),
481 ordered,
482 );
483 assert.deepEqual(
484 [...track.querySelectorAll("thead th")].map((th) => th.textContent).slice(-2),
485 ["Tokens", "Result"],
486 );
487 assert.deepEqual(
488 [...c.root.querySelectorAll(".race-results thead th")].map((th) => th.textContent).slice(-2),
489 ["Tokens", "Result"],
490 );
491 assert.equal(track.querySelectorAll(".lane-marker-approved").length, 3);
492 assert.equal(track.querySelectorAll(".lane-marker-review").length, 3);
493 assert.equal(track.querySelectorAll(".race-mark-box").length, 18);
494 assert.equal(c.root.querySelector(".race-compare")!.textContent!.includes("25:00.0"), true);
495 } finally {
496 c.close();
497 }
498});
499
500test("budget figures appear once per source with separate freshness and no within-budget dot", () => {
501 const state = fixture("usage-both");
502 const html = renderToStaticMarkup(createElement(TooltipProvider, null,
503 createElement(BudgetUsage, { usage: state.races![0].entrants[0].usage, budget: 1000000, status: "within", agent: "fixture-agent", brand }),
504 ));
505 const dom = new JSDOM(html);
506 const figures = [...dom.window.document.querySelectorAll(".usage-figure")].map((el) => el.textContent);
507 assert.deepEqual(figures, ["420k / 1M tokens 路 reported", "250k / 1M tokens 路 metered"]);
508 assert.equal(dom.window.document.querySelectorAll("meter").length, 1);
509 assert.equal(dom.window.document.querySelector("meter")!.value, 250000);
510 assert.equal(dom.window.document.querySelector(".token-budget-state")!.textContent, "Within budget");
511 assert.ok([...dom.window.document.querySelectorAll(".usage-freshness")].every((el) => el.textContent!.startsWith("as of ")));
512});
513
514test("Compare and Results count passing receipts rather than checks; full ties have no best caption", async () => {
515 const c = setup("usage-race", "#race/FH-040", true, false, (wire) => {
516 const race = wire.races![0];
517 const r = wire.reviews[0];
518 // One passed receipt has three passing checks; a second failed receipt makes it 1 of 2.
519 wire.reviews.push({ ...structuredClone(r), id: "previous-receipt", createdAt: race.entrants[0].claimedAt,
520 receipt: { ...structuredClone(r.receipt!), status: "failed" } });
521 for (const e of race.entrants) {
522 e.approvedAt = race.entrants[0].approvedAt;
523 e.usage = structuredClone(race.entrants[0].usage);
524 }
525 });
526 try {
527 await until(() => c.calls.filter((call) => call.url.pathname.includes("/reviews/")).length === 3 &&
528 [...c.root.querySelectorAll(".race-compare tbody tr")].find((row) => row.querySelector("th")?.textContent === "Files changed")?.textContent?.includes("4"));
529 const facts = [...c.root.querySelectorAll(".race-compare tbody tr")];
530 const checks = facts.find((row) => row.querySelector("th")?.textContent === "Checks passed")!;
531 assert.deepEqual([...checks.querySelectorAll(".compare-value")].map((cell) => cell.textContent), ["1 of 2", "1 of 1", "1 of 1"]);
532 assert.deepEqual([...c.root.querySelectorAll('.race-results [data-label="Checks passed"]')].map((cell) => cell.textContent), ["1 of 2", "1 of 1", "1 of 1"]);
533 assert.doesNotMatch(c.root.querySelector(".race-compare")!.textContent!, /fewest|fastest/);
534 assert.equal(c.root.querySelectorAll(".compare-entrant .race-saddlecloth").length, facts.length * 3);
535 assert.deepEqual([...facts[0].querySelectorAll(".compare-entrant > span:last-child")].map((el) => el.textContent), ["fixture-agent", "fixture-peer", "fixture-third"]);
536 } finally { c.close(); }
537});
538