g1t/apps/web/app/lib/billing.test.ts

253 lines12,713 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.

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
Usage lists Other once: kinds of work without words of their own are added into it5 foldTasks,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas6 gigabytes,
7 shownMeters,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look8 alertText,
9 alertTone,
10 cardCheckResult,
11 dollars,
12 needsAttention,
13 usageGlance,
14 parseCaps,
15 parseLimitRequest,
16 parsePrepay,
17 parseSpendLimit,
18 planStatus,
19 readDollars,
20 requestStatus,
21 share,
22 spendPath,
23 spendRange,
24 wholeDollars,
25} from "./billing.ts";
26
27test("money reads as dollars", () => {
28 assert.equal(dollars(9_500_000), "$9.50");
29 assert.equal(dollars(-1_250_000), "−$1.25");
30 assert.equal(wholeDollars(1_000_000_000), "$1,000");
31 assert.equal(wholeDollars(100_000), "$0.10");
32 assert.equal(readDollars("$1,000"), 1_000_000_000);
33 assert.equal(readDollars(""), null);
34 assert.equal(readDollars("lots"), null);
35});
36
37test("a prepayment is $25 or more, by card up to $10,000, by bank transfer from $1,000", () => {
38 assert.deepEqual(parsePrepay({ amount: "100" }), { ok: true, value: { amountCents: 10_000, method: "card" } });
39 assert.deepEqual(parsePrepay({ amount: "100", custom: "250" }), {
40 ok: true,
41 value: { amountCents: 25_000, method: "card" },
42 });
43 assert.equal(parsePrepay({ custom: "10" }).ok, false);
44 assert.equal(parsePrepay({ custom: "20000" }).ok, false);
45 assert.equal(parsePrepay({ custom: "500", method: "bank_transfer" }).ok, false);
46 assert.deepEqual(parsePrepay({ custom: "20000", method: "bank_transfer" }), {
47 ok: true,
48 value: { amountCents: 2_000_000, method: "bank_transfer" },
49 });
50 assert.equal(parsePrepay({}).ok, false);
51});
52
53test("caps stay in range, and empty goes back to the default", () => {
54 assert.deepEqual(parseCaps({ run: "", issue: "" }), { ok: true, value: { runCapMicros: null, issueCapMicros: null } });
55 assert.deepEqual(parseCaps({ run: "0.10", issue: "1000" }), {
56 ok: true,
57 value: { runCapMicros: 100_000, issueCapMicros: 1_000_000_000 },
58 });
59 assert.equal(parseCaps({ run: "0.05" }).ok, false);
60 assert.equal(parseCaps({ issue: "2000" }).ok, false);
61 assert.equal(parseCaps({ run: "two" }).ok, false);
62});
63
64test("a limit request needs an amount, a reason and a monthly spend; an overage only a reason", () => {
65 assert.deepEqual(parseLimitRequest({ kind: "limit", amount: "5000", reason: " A launch ", expected: "3000" }), {
66 ok: true,
67 value: { kind: "limit", amountMicros: 5_000_000_000, reason: "A launch", expectedMonthlyMicros: 3_000_000_000 },
68 });
69 assert.equal(parseLimitRequest({ kind: "limit", amount: "5000", reason: "" , expected: "1" }).ok, false);
70 assert.equal(parseLimitRequest({ kind: "limit", reason: "x", expected: "1" }).ok, false);
71 assert.deepEqual(parseLimitRequest({ kind: "overage", reason: "A loop ran all night" }), {
72 ok: true,
73 value: { kind: "overage", amountMicros: 0, reason: "A loop ran all night", expectedMonthlyMicros: 0 },
74 });
75});
76
77test("a spend limit is automatic, fixed, the full amount available, or the one-time raise", () => {
78 assert.deepEqual(parseSpendLimit({ mode: "automatic" }), { ok: true, value: { micros: null, useFull: false, raiseOnce: false } });
79 assert.deepEqual(parseSpendLimit({ mode: "fixed", limit: "500" }), {
80 ok: true,
81 value: { micros: 500_000_000, useFull: false, raiseOnce: false },
82 });
83 assert.equal(parseSpendLimit({ mode: "fixed", limit: "0.5" }).ok, false);
84 assert.deepEqual(parseSpendLimit({ mode: "full" }), { ok: true, value: { micros: null, useFull: true, raiseOnce: false } });
85 assert.deepEqual(parseSpendLimit({ mode: "raise" }), { ok: true, value: { micros: null, useFull: false, raiseOnce: true } });
86 assert.deepEqual(parseSpendLimit({ mode: "raise", limit: "150" }), {
87 ok: true,
88 value: { micros: 150_000_000, useFull: false, raiseOnce: true },
89 });
90});
91
92test("the spend limit's range: up to the highest ceiling plus prepaid, then once to twice it, then ask", () => {
93 // A first month at $100, nothing prepaid, the raise unused: $100 alone, $200 once.
94 const range = spendRange({ availableMicros: 100_000_000, ceilingMicros: 100_000_000, raiseOnceMicros: 200_000_000, raisedAt: null });
95 assert.deepEqual(range, { selfServeMicros: 100_000_000, raiseOnceMicros: 200_000_000, raisedAt: null });
96 assert.equal(spendPath(80_000_000, range), "self");
97 assert.equal(spendPath(100_000_000, range), "self");
98 assert.equal(spendPath(150_000_000, range), "raise");
99 assert.equal(spendPath(200_000_000, range), "raise");
100 assert.equal(spendPath(200_000_001, range), "ask");
101 // The raise used: only asking goes further.
102 const used = spendRange({ availableMicros: 200_000_000, ceilingMicros: 200_000_000, raiseOnceMicros: null, raisedAt: "2026-10-01T00:00:00Z" });
103 assert.equal(used.raiseOnceMicros, null);
104 assert.equal(spendPath(300_000_000, used), "ask");
105 // No ceiling: anything goes.
106 assert.equal(spendPath(1e12, spendRange({ availableMicros: null, ceilingMicros: null, raiseOnceMicros: null })), "self");
107 // A raise no higher than what is available is no raise.
108 assert.equal(spendRange({ availableMicros: 300_000_000, ceilingMicros: 100_000_000, raiseOnceMicros: 300_000_000 }).raiseOnceMicros, null);
109});
110
111test("the plan card says where the workspace stands", () => {
112 const free = { plan: "free" as const, trialMicrosLeft: 0, trialVerified: false, firstMonth: false };
113 assert.deepEqual(planStatus(null, free), { kind: "free", label: "Free" });
114 assert.equal(planStatus(null, { ...free, trialVerified: true, trialMicrosLeft: 5_000_000 }).kind, "trial");
115 assert.equal(planStatus(null, { ...free, trialVerified: true }).kind, "free");
116 const subscription = { feature: "plan" as const, status: "active" as const, periodEnd: null, startedBy: "a", startedAt: "" };
117 assert.deepEqual(planStatus({ on: true, subscription }, { ...free, plan: "paid", firstMonth: true }), {
118 kind: "paid",
119 label: "On the g1t plan, first month",
120 });
121 assert.equal(planStatus({ on: true, subscription: { ...subscription, status: "canceling" } }, { ...free, plan: "paid" }).kind, "canceling");
122 assert.equal(planStatus({ on: false, subscription: { ...subscription, status: "past_due" } }, free).kind, "past_due");
123 assert.equal(planStatus({ on: true, included: true, subscription: null }, free).kind, "comped");
124 assert.equal(planStatus(null, { ...free, plan: "internal" }).kind, "comped");
125 assert.equal(planStatus(null, { ...free, plan: "enterprise" }).kind, "enterprise");
126});
127
128test("the overview's Usage card reads the month by what pays", () => {
129 const usage = {
130 free: false,
131 spentMicros: 14_000_000,
132 usedMicros: 11_000_000,
133 byTask: [
134 { key: "review", micros: 2_000_000, runs: 4 },
135 { key: "implement", micros: 12_000_000, runs: 9 },
136 { key: "plan", micros: 0, runs: 1 },
137 ],
138 };
139 const entitlements = { includedMicros: 10_000_000, includedUsedMicros: 10_000_000, trialMicrosLeft: 0 };
140 const plan = usageGlance({ usage, status: { kind: "paid", label: "" }, entitlements, limit: { spentMicros: 4_000_000, spendLimitMicros: 200_000_000 }, trialMicros: 5_000_000 });
141 assert.equal(plan.kind, "plan");
142 assert.deepEqual(plan.credit, { label: "Included usage", usedMicros: 10_000_000, ofMicros: 10_000_000 });
143 assert.deepEqual(plan.onDemand, { micros: 4_000_000, limitMicros: 200_000_000 });
144 // Most first, and nothing that cost nothing.
145 assert.deepEqual(plan.lines.map((line) => line.label), ["Making changes", "Reviews"]);
146 const trial = usageGlance({ usage, status: { kind: "trial", label: "" }, entitlements: { ...entitlements, trialMicrosLeft: 1_500_000 }, limit: null, trialMicros: 5_000_000 });
147 assert.deepEqual(trial.credit, { label: "Trial credit", usedMicros: 3_500_000, ofMicros: 5_000_000 });
148 assert.equal(trial.onDemand, null);
149 assert.equal(usageGlance({ usage, status: { kind: "comped", label: "" }, entitlements, limit: null, trialMicros: 0 }).kind, "comped");
150 assert.equal(usageGlance({ usage, status: { kind: "free", label: "" }, entitlements, limit: null, trialMicros: 0 }).kind, "forge");
151 // While g1t charges nothing, usage is shown at cost.
152 const beta = usageGlance({ usage: { ...usage, free: true }, status: { kind: "paid", label: "" }, entitlements, limit: null, trialMicros: 0 });
153 assert.equal(beta.kind, "beta");
154 assert.equal(beta.spentMicros, 11_000_000);
155});
156
157test("a meter's share stays between 0 and 1", () => {
158 assert.equal(share(5, 10), 0.5);
159 assert.equal(share(15, 10), 1);
160 assert.equal(share(5, 0), 0);
161 assert.equal(share(5, null), 0);
162});
163
164test("after a card check the owner reads whether the trial started", () => {
165 assert.match(cardCheckResult({ trialVerified: true, trialMicrosLeft: 5_000_000 }, 5_000_000), /[$]5 trial is ready/);
166 assert.match(cardCheckResult({ trialVerified: true, trialMicrosLeft: 0 }, 5_000_000), /Prepaid cards can still pay for the plan/);
167 assert.match(cardCheckResult({ trialVerified: false, trialMicrosLeft: 0 }, 5_000_000), /did not finish/);
168});
169
170test("alerts read as sentences", () => {
171 const alert = { meter: "included", level: 90, usedMicros: 9_000_000, limitMicros: 10_000_000, message: "" };
172 assert.equal(alertText(alert), "90% of the plan's included usage: $9.00 of $10.00.");
173 assert.equal(alertText({ ...alert, meter: "spend_limit", level: 100 }), "All of your spend limit: $9.00 of $10.00.");
174 assert.equal(alertTone(50), "ok");
175 assert.equal(alertTone(75), "warning");
176 assert.equal(alertTone(100), "stopped");
177});
178
179test("a workspace needs attention when paused, on a spike, or at 90%", () => {
180 assert.equal(needsAttention(null), false);
181 assert.equal(needsAttention({ paused: null, spike: null, alerts: [] }), false);
182 assert.equal(needsAttention({ paused: "Spend spike", spike: null, alerts: [] }), true);
183 const spike = { id: "s", status: "continued", hourMicros: 1, averageMicros: 1, detectedAt: "" };
184 assert.equal(needsAttention({ paused: null, spike, alerts: [] }), false);
185 assert.equal(needsAttention({ paused: null, spike: { ...spike, status: "open" }, alerts: [] }), true);
186 const at = (level: number) => ({ meter: "spend_limit", level, usedMicros: 0, limitMicros: 0, message: "" });
187 assert.equal(needsAttention({ paused: null, spike: null, alerts: [at(75)] }), false);
188 assert.equal(needsAttention({ paused: null, spike: null, alerts: [at(90)] }), true);
189});
190
191test("a request says where it stands", () => {
192 const request = {
193 id: "r",
194 workspace: "acme",
195 kind: "limit",
196 amountMicros: 1,
197 reason: "",
198 expectedMonthlyMicros: 0,
199 status: "open",
200 createdBy: "a",
201 createdAt: "",
202 };
203 assert.equal(requestStatus(request), "Waiting for an answer");
204 assert.equal(requestStatus({ ...request, status: "approved", decidedMicros: 2_000_000_000 }), "Approved at $2,000");
205 assert.equal(requestStatus({ ...request, status: "declined" }), "Declined");
206});
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas207
208const METERS = [
209 { key: "agents", label: "Agents & sandboxes", micros: 1_200_000, quantity: "4 runs" },
210 { key: "builds", label: "Builds", micros: 0, quantity: null },
211 { key: "requests", label: "Requests & CPU", micros: 0, quantity: null },
212 { key: "domains", label: "Custom domains", micros: 120_000, quantity: "1 custom domain" },
213 { key: "git_storage", label: "Git operations & storage", micros: 0, quantity: "1,200 git operations" },
214 { key: "search_scans", label: "Search & security scans", micros: 3_000, quantity: null },
215];
216
217test("the plan shows every meter, with no quota beside any of them", () => {
218 const shown = shownMeters(METERS, true);
219 assert.deepEqual(
220 shown.map((m) => m.key),
221 ["agents", "builds", "requests", "domains", "git_storage", "search_scans"],
222 );
223 for (const meter of shown) assert.ok(!/ of |apps up/i.test(`${meter.label} ${meter.quantity ?? ""}`));
224});
225
226test("a free workspace sees only what it can use, and anything it used anyway", () => {
227 assert.deepEqual(
228 shownMeters(METERS, false).map((m) => m.key),
229 ["agents", "domains", "git_storage", "search_scans"],
230 );
231});
232
233test("storage reads in powers of ten", () => {
234 assert.equal(gigabytes(1_000_000_000), "1 GB");
235 assert.equal(gigabytes(1_500_000_000), "1.5 GB");
236 assert.equal(gigabytes(500_000_000), "500 MB");
237});
Usage lists Other once: kinds of work without words of their own are added into it238
239test("kinds of work without words of their own are one Other, listed once and last", () => {
240 const slices = [
241 { key: "check", micros: 5, runs: 50 },
242 { key: "review", micros: 3, runs: 5 },
243 { key: "other", micros: 1, runs: 7 },
244 { key: "implement", micros: 9, runs: 4 },
245 { key: "answer", micros: 2, runs: 11 },
246 ];
247 assert.deepEqual(foldTasks(slices), [
248 { key: "review", micros: 3, runs: 5 },
249 { key: "implement", micros: 9, runs: 4 },
250 { key: "other", micros: 8, runs: 68 },
251 ]);
252 assert.deepEqual(foldTasks([{ key: "plan", micros: 1, runs: 1 }]), [{ key: "plan", micros: 1, runs: 1 }]);
253});