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

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