Fork Horse repository, listed by its owner. Publisher snapshot.

packages/forkhorse-dashboard/test/usage.test.ts

Snapshot at 34e3175

Containing directory

22,690 bytes 路 typescriptView raw
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