Skip to content

g1t/services/billing/src/margin.rs

2,113 lines100,037 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.

Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1//! What g1t earns on each thing it sells, measured against what
2//! Cloudflare actually charged for it.
3//!
4//! Once a day, after `costs` has read Cloudflare's bill, the reconciler
5//! puts three figures side by side for every day and each of g1t's
6//! products (a "bucket": sandboxes, deployments, git, repository storage,
7//! …):
8//!
9//! 1. **What Cloudflare charged**: the day's cost lines `cost_map` gives
10//! the bucket.
11//! 2. **What g1t's meters recorded**: the cost on the ledger's entries for
12//! it (the price book's cost at the time) and, where a mapping names
13//! one, g1t's own count of the same units (git operations).
14//! 3. **What customers were charged**: the entries' value at price, before
15//! the plan's included usage, a trial or a pool paid part of it; and of
16//! that, what workspaces paid. Month-end meters (git, storage, scans,
17//! embeddings, the actions cache) come from daily snapshots of what they
18//! had come to (`pending_days`). The plan's price is the `platform`
19//! bucket's: the plan pays for running g1t.
20//!
21//! From those: margin per product (value against cost) and for all of g1t
22//! (money in against every cost); drift (counts or costs that disagree past
23//! a mapping's threshold, and leaks: cost with no revenue, or a Cloudflare
24//! meter no one mapped); each workspace's cost, Cloudflare's figure shared
25//! out by each workspace's own meters; and price proposals when a unit's
26//! real cost has moved (`pricing`). Alerts go to staff by email and as a
27//! banner in sudo. See docs/BILLING_OPERATIONS.md.
28
29use std::collections::{BTreeMap, BTreeSet};
30
31use g1t_contracts::billing::*;
32use g1t_contracts::{FailureCode, Outcome, new_id};
33use g1t_contracts::time::rfc3339;
34use g1t_kit::now_ms;
35use serde::{Deserialize, Serialize};
36use worker::wasm_bindgen::JsValue;
37use worker::{Env, Result};
38
39use crate::Billing;
40use crate::costs::{self, ARTIFACTS_OPERATIONS, DAY_MS, Rule, SOURCE_ARTIFACTS, SOURCE_BILLABLE, UNMAPPED};
41
42/// Buckets that are the cost of running g1t, paid by the plan rather than
43/// sold by the unit: never a leak for having no revenue of their own.
44pub(crate) const OVERHEAD: [&str; 1] = ["platform"];
45/// Buckets Cloudflare does not bill: their cost is g1t's own figure.
46pub(crate) const NOT_CLOUDFLARE: [&str; 1] = ["models"];
47/// The days drift is judged over.
48const DRIFT_DAYS: u64 = 7;
49/// The days a workspace's cost is set against its revenue.
50const ANOMALY_DAYS: u64 = 30;
51/// The days a unit's cost is measured over.
52const MEASURE_DAYS: u64 = 30;
53/// Fewer of g1t's units than this say nothing about cost per unit.
54const MIN_UNITS: f64 = 1_000.0;
55/// An open alert is emailed again after this long.
56const REMIND_MS: u64 = 7 * DAY_MS;
57
58// ---------------------------------------------------------------------
59// The arithmetic, apart from the database so it can be tested.
60// ---------------------------------------------------------------------
61
62/// One of g1t's products on one day.
63#[derive(Clone, Debug, Default, PartialEq)]
64pub(crate) struct ProductDay {
65 pub day: String,
66 pub bucket: String,
67 /// What Cloudflare charged g1t, in millionths of a dollar.
68 pub cf_cost_micros: i64,
69 /// What g1t's meters recorded it cost (the price book's cost).
70 pub own_cost_micros: i64,
71 /// What customers were charged for it at price, before what paid.
72 pub value_micros: i64,
73 /// Of that, what workspaces paid themselves.
74 pub cash_micros: i64,
75 /// Units Cloudflare counted and units g1t counted, where a mapping
76 /// says they are the same units.
77 pub cf_quantity: f64,
78 pub own_quantity: f64,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it79 /// Of `cost()`, what went on usage g1t gave away (the workspaces'
80 /// `WorkspaceDay::given`, added up).
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running81 pub given: Given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily82}
83
84impl ProductDay {
85 /// What it cost: Cloudflare's figure where Cloudflare bills it, else
86 /// g1t's own (models are billed by their providers, through the gateway).
87 pub fn cost(&self) -> i64 {
88 if NOT_CLOUDFLARE.contains(&self.bucket.as_str()) { self.own_cost_micros } else { self.cf_cost_micros }
89 }
90}
91
92/// A line of Cloudflare's bill, as stored.
93#[derive(Clone, Debug, Deserialize)]
94pub(crate) struct LineRow {
95 pub day: String,
96 pub source: String,
97 pub product: String,
98 pub meter: String,
99 pub quantity: f64,
100 pub cost_usd: f64,
101}
102
103/// A count of g1t's own, as stored.
104#[derive(Clone, Debug, Deserialize)]
105pub(crate) struct OwnRow {
106 pub day: String,
107 pub meter: String,
108 pub workspace: String,
109 pub quantity: f64,
110}
111
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running112/// What g1t gave away, by why: its own comped workspaces, free use (a
113/// free period, free allowances, overruns g1t covered), the trial, and the
Merge branch 'worktree-agent-a633ac0f7f66d419d'114/// open-source pool, and discounts on an account's terms (what they took
115/// below cost plus the margin, `ledger.discount_micros`). The Team plan's
116/// included usage is paid for by the plan's price, so it is sold, not given.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running117#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
118pub(crate) struct Given {
119 pub comped: i64,
120 pub free: i64,
121 pub trial: i64,
122 pub pool: i64,
Merge branch 'worktree-agent-a633ac0f7f66d419d'123 pub discount: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running124}
125
126impl Given {
127 pub fn total(&self) -> i64 {
Merge branch 'worktree-agent-a633ac0f7f66d419d'128 self.comped + self.free + self.trial + self.pool + self.discount
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running129 }
130
131 fn add(&mut self, other: &Given) {
132 self.comped += other.comped;
133 self.free += other.free;
134 self.trial += other.trial;
135 self.pool += other.pool;
Merge branch 'worktree-agent-a633ac0f7f66d419d'136 self.discount += other.discount;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running137 }
138
139 /// The same shares of `cost` as these are of `value`, at most all of it.
140 fn of(&self, cost: i64, value: i64) -> Given {
141 let total = self.total();
142 if value <= 0 || cost <= 0 || total <= 0 {
143 return Given::default();
144 }
145 let given = cost as i128 * total.min(value) as i128 / value as i128;
146 let part = |x: i64| (given * x.max(0) as i128 / total as i128) as i64;
Merge branch 'worktree-agent-a633ac0f7f66d419d'147 Given {
148 comped: part(self.comped),
149 free: part(self.free),
150 trial: part(self.trial),
151 pool: part(self.pool),
152 discount: part(self.discount),
153 }
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running154 }
155}
156
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily157/// What a workspace was charged for one key on one day.
158#[derive(Clone, Debug, Default, PartialEq)]
159pub(crate) struct UsageRow {
160 pub day: String,
161 pub workspace: String,
162 /// A ledger task (or `builds`), a month-end source, or `plan`.
163 pub key: String,
164 pub value: i64,
165 pub cash: i64,
166 pub cost: i64,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it167 /// Of `value`, what g1t gave away: all of it for g1t's own (comped)
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running168 /// workspaces and in a free period, else what the trial and the pool
169 /// paid and the overruns g1t covered.
170 pub given: Given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily171}
172
173/// One workspace's share of a product's cost on one day.
174#[derive(Clone, Debug, PartialEq)]
175pub(crate) struct WorkspaceDay {
176 pub day: String,
177 pub workspace: String,
178 pub bucket: String,
179 pub cost: i64,
Margin alerts measure what is sold, and say dollars when a percentage would mislead180 /// What the workspace paid in cash.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily181 pub revenue: i64,
Margin alerts measure what is sold, and say dollars when a percentage would mislead182 /// What its usage was priced at, whoever paid for it.
183 pub value: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running184 /// Of `cost`, the part g1t gave away: all of it for a comped workspace
185 /// or one with nothing priced that day (free use), else the cost times
186 /// the shares of its usage that day that g1t paid for.
187 pub given: Given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily188}
189
190fn micros(dollars: f64) -> i64 {
191 (dollars * 1_000_000.0).round() as i64
192}
193
194/// Puts the day's bill, g1t's counts and what customers were charged side
195/// by side, a row per day and bucket, and shares each bucket's cost out
196/// to workspaces.
197pub(crate) fn fold(
198 rules: &[Rule],
199 revenue_map: &BTreeMap<String, String>,
200 lines: &[LineRow],
201 own: &[OwnRow],
202 usage: &[UsageRow],
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running203 internal: &BTreeSet<String>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily204) -> (Vec<ProductDay>, Vec<WorkspaceDay>) {
205 let mut days: BTreeMap<(String, String), ProductDay> = BTreeMap::new();
206 let entry = |day: &str, bucket: &str| -> ProductDay {
207 ProductDay { day: day.to_owned(), bucket: bucket.to_owned(), ..ProductDay::default() }
208 };
209 // Which of g1t's own meters count each bucket's units.
210 let mut own_meters: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
211 for rule in rules {
212 if let Some(meter) = &rule.own_meter {
213 own_meters.entry(rule.bucket.as_str()).or_default().insert(meter.as_str());
214 }
215 }
216 let mut events: BTreeMap<(String, String), f64> = BTreeMap::new();
217 for line in lines {
218 let rule = costs::classify(rules, &line.product, &line.meter);
219 let bucket = rule.map_or(UNMAPPED, |r| r.bucket.as_str());
220 let key = (line.day.clone(), bucket.to_owned());
221 if line.source == SOURCE_ARTIFACTS {
222 // What Artifacts counted: operations only, and only where the
223 // bill does not count them itself.
224 if ARTIFACTS_OPERATIONS.contains(&line.meter.as_str()) {
225 *events.entry(key).or_default() += line.quantity;
226 }
227 continue;
228 }
229 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
230 row.cf_cost_micros += micros(line.cost_usd);
231 if line.source == SOURCE_BILLABLE && rule.is_some_and(|r| r.own_meter.is_some()) {
232 row.cf_quantity += line.quantity;
233 }
234 }
235 for (key, quantity) in events {
236 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
237 if row.cf_quantity == 0.0 {
238 row.cf_quantity = quantity;
239 }
240 }
241 // g1t's own counts of the same units, by bucket and by workspace.
242 let mut own_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
243 // Cloudflare's own count by workspace, where it gives one
244 // (`cloudflare_<bucket>`): the best way to share its cost.
245 let mut cf_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
246 for count in own {
247 if let Some(bucket) = count.meter.strip_prefix("cloudflare_") {
248 cf_by.entry((count.day.clone(), bucket.to_owned())).or_default().push((count.workspace.clone(), count.quantity));
249 continue;
250 }
251 for (bucket, meters) in &own_meters {
252 if meters.contains(count.meter.as_str()) {
253 let key = (count.day.clone(), (*bucket).to_owned());
254 days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1)).own_quantity += count.quantity;
255 own_by.entry(key).or_default().push((count.workspace.clone(), count.quantity));
256 }
257 }
258 }
259 // What customers were charged.
260 let bucket_of = |key: &str| revenue_map.get(key).cloned().unwrap_or_else(|| "models".to_owned());
261 let mut value_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
262 let mut cost_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
263 let mut revenue: BTreeMap<(String, String, String), i64> = BTreeMap::new();
Margin alerts measure what is sold, and say dollars when a percentage would mislead264 let mut valued: BTreeMap<(String, String, String), i64> = BTreeMap::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily265 let mut active: BTreeMap<String, Vec<(String, f64)>> = BTreeMap::new();
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running266 let mut gave: BTreeMap<(String, String), (Given, i64)> = BTreeMap::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily267 for u in usage {
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it268 let g = gave.entry((u.day.clone(), u.workspace.clone())).or_default();
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running269 g.0.add(&u.given);
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it270 g.1 += u.value;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily271 let bucket = bucket_of(&u.key);
272 let key = (u.day.clone(), bucket.clone());
273 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
274 row.own_cost_micros += u.cost;
275 row.value_micros += u.value;
276 row.cash_micros += u.cash;
277 value_by.entry(key.clone()).or_default().push((u.workspace.clone(), u.value as f64));
278 cost_by.entry(key).or_default().push((u.workspace.clone(), u.cost as f64));
Margin alerts measure what is sold, and say dollars when a percentage would mislead279 *revenue.entry((u.day.clone(), u.workspace.clone(), bucket.clone())).or_default() += u.cash;
280 *valued.entry((u.day.clone(), u.workspace.clone(), bucket)).or_default() += u.value;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily281 active.entry(u.day.clone()).or_default().push((u.workspace.clone(), u.value.max(u.cost) as f64));
282 }
283 // Each bucket's cost shared out: by Cloudflare's own count per
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running284 // workspace, else by g1t's own count of its units, else by what its
285 // usage cost (so free use carries its own cost), else by what it was
286 // charged; running g1t, and what no one mapped, by each workspace's
287 // share of all usage that day.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily288 let mut shares: BTreeMap<(String, String, String), i64> = BTreeMap::new();
289 for ((day, bucket), row) in &days {
290 let key = (day.clone(), bucket.clone());
291 let weigh = |m: &BTreeMap<(String, String), Vec<(String, f64)>>| m.get(&key).filter(|w| w.iter().any(|(_, v)| *v > 0.0)).cloned();
292 let weights = if OVERHEAD.contains(&bucket.as_str()) || bucket == UNMAPPED {
293 active.get(day).cloned()
294 } else {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running295 weigh(&cf_by).or_else(|| weigh(&own_by)).or_else(|| weigh(&cost_by)).or_else(|| weigh(&value_by)).or_else(|| active.get(day).cloned())
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily296 };
297 for (workspace, micros) in attribute(row.cost(), &weights.unwrap_or_default()) {
298 *shares.entry((day.clone(), workspace, bucket.clone())).or_default() += micros;
299 }
300 }
301 let keys: BTreeSet<(String, String, String)> = shares.keys().chain(revenue.keys()).cloned().collect();
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it302 let workspaces: Vec<WorkspaceDay> = keys
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily303 .into_iter()
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it304 .map(|(day, workspace, bucket)| {
305 let cost = shares.get(&(day.clone(), workspace.clone(), bucket.clone())).copied().unwrap_or(0);
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running306 // The day's shares given away apply to every bucket, so a
307 // comped workspace's part of running g1t is given too. A
308 // workspace with nothing priced that day used g1t for free.
309 let given = if internal.contains(&workspace) {
310 Given { comped: cost, ..Given::default() }
311 } else {
312 match gave.get(&(day.clone(), workspace.clone())) {
313 Some((given, value)) if *value > 0 => given.of(cost, *value),
314 _ => Given { free: cost.max(0), ..Given::default() },
315 }
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it316 };
317 WorkspaceDay {
318 cost,
319 revenue: revenue.get(&(day.clone(), workspace.clone(), bucket.clone())).copied().unwrap_or(0),
320 value: valued.get(&(day.clone(), workspace.clone(), bucket.clone())).copied().unwrap_or(0),
321 given,
322 day,
323 workspace,
324 bucket,
325 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily326 })
327 .collect();
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it328 for w in &workspaces {
329 if let Some(row) = days.get_mut(&(w.day.clone(), w.bucket.clone())) {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running330 row.given.add(&w.given);
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it331 }
332 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily333 (days.into_values().collect(), workspaces)
334}
335
336/// A month-end source's day, from the snapshots of what it had come to:
337/// each day's figure less the day before's in the same month (the first
338/// day of a month, or the first snapshot, is its own).
339pub(crate) fn pending_deltas(snapshots: &[(String, String, String, i64, i64)]) -> Vec<UsageRow> {
340 // (day, workspace, source, cost, charge), any order.
341 let mut sorted = snapshots.to_vec();
342 sorted.sort_by(|a, b| (&a.1, &a.2, &a.0).cmp(&(&b.1, &b.2, &b.0)));
343 let mut out = Vec::new();
344 let mut previous: Option<&(String, String, String, i64, i64)> = None;
345 for snap in &sorted {
346 let (day, workspace, source, cost, charge) = snap;
347 let (before_cost, before_charge) = match previous {
348 Some(p) if p.1 == *workspace && p.2 == *source && p.0[..7] == day[..7] => (p.3, p.4),
349 _ => (0, 0),
350 };
351 let (cost, charge) = ((cost - before_cost).max(0), (charge - before_charge).max(0));
352 if cost > 0 || charge > 0 {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running353 out.push(UsageRow { day: day.clone(), workspace: workspace.clone(), key: source.clone(), value: charge, cash: charge, cost, given: Given::default() });
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily354 }
355 previous = Some(snap);
356 }
357 out
358}
359
360/// Margin as a share of what was charged, in percent; None when nothing was.
361pub(crate) fn margin_percent(revenue_micros: i64, cost_micros: i64) -> Option<f64> {
362 (revenue_micros > 0).then(|| (revenue_micros - cost_micros) as f64 * 100.0 / revenue_micros as f64)
363}
364
365/// How far `ours` is from `theirs`, in percent of theirs; None when theirs
366/// is nothing.
367pub(crate) fn delta_percent(ours: f64, theirs: f64) -> Option<f64> {
368 (theirs > 0.0).then(|| (ours - theirs) * 100.0 / theirs)
369}
370
371#[derive(Clone, Copy, Debug, PartialEq, Eq)]
372pub(crate) enum DriftKind {
373 /// g1t counted a different number of units than Cloudflare did.
374 Count,
375 /// What Cloudflare charged differs from what the price book says the
376 /// same usage cost.
377 Cost,
378 /// Cloudflare charged for something nothing charges customers for.
379 Leak,
Merge branch 'worktree-agent-a633ac0f7f66d419d'380 /// Model usage AI Gateway put no price on: its cost is not what the
381 /// provider bills, so neither the ledger nor the gateway total has it.
382 Unpriced,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily383}
384
385impl DriftKind {
386 pub fn as_str(self) -> &'static str {
387 match self {
388 DriftKind::Count => "count",
389 DriftKind::Cost => "cost",
390 DriftKind::Leak => "leak",
Merge branch 'worktree-agent-a633ac0f7f66d419d'391 DriftKind::Unpriced => "unpriced",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily392 }
393 }
394}
395
396#[derive(Clone, Debug, PartialEq)]
397pub(crate) struct Drift {
398 pub bucket: String,
399 pub kind: DriftKind,
400 pub ours: f64,
401 pub cloudflare: f64,
402 pub delta_percent: Option<f64>,
403}
404
405/// Drift over a window for one bucket: counts more than `threshold`
406/// percent apart, a bill that far from the price book's cost of the same
407/// usage, and cost with nothing charged for it. Under `min_cost_micros`
408/// in all, cost says nothing.
409pub(crate) fn drifts(bucket: &str, days: &[ProductDay], threshold: f64, counted: bool, min_cost_micros: i64) -> Vec<Drift> {
410 let overhead = OVERHEAD.contains(&bucket);
411 let sum = |f: &dyn Fn(&ProductDay) -> f64| days.iter().map(f).sum::<f64>();
412 let cf_cost = sum(&|d| d.cf_cost_micros as f64);
413 let own_cost = sum(&|d| d.own_cost_micros as f64);
414 let value = sum(&|d| d.value_micros as f64);
Costs: counts are compared with Cloudflare's from the day g1t started counting, so days before a meter existed are not drift415 // Counts are compared from the first day g1t counted: before its meter
416 // was deployed there is only Cloudflare's side. A meter that never
417 // counted anything is compared over every day, so it still shows.
418 let first_counted = days.iter().filter(|d| d.own_quantity > 0.0).map(|d| d.day.as_str()).min();
419 let compared = |d: &&ProductDay| first_counted.is_none_or(|from| d.day.as_str() >= from);
420 let (cf_quantity, own_quantity) = days.iter().filter(compared).fold((0.0, 0.0), |(cf, own), d| (cf + d.cf_quantity, own + d.own_quantity));
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily421 let mut out = Vec::new();
422 if counted && cf_quantity > 0.0 {
423 let delta = delta_percent(own_quantity, cf_quantity);
424 if delta.is_some_and(|d| d.abs() > threshold) {
425 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Count, ours: own_quantity, cloudflare: cf_quantity, delta_percent: delta });
426 }
427 }
428 let enough = cf_cost.max(own_cost) >= min_cost_micros as f64;
Merge branch 'worktree-agent-a633ac0f7f66d419d'429 // Models: what AI Gateway priced g1t's own provider traffic at (its
430 // lines, as "Cloudflare's" side) against the ledger's model cost. Only
431 // once the gateway has been read; then the ledger having none of it is
432 // drift too (traffic no run was charged for).
433 let models = NOT_CLOUDFLARE.contains(&bucket) && cf_cost > 0.0;
434 if enough && !overhead && cf_cost > 0.0 && (own_cost > 0.0 || models) {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily435 let delta = delta_percent(own_cost, cf_cost);
436 if delta.is_some_and(|d| d.abs() > threshold) {
437 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Cost, ours: own_cost, cloudflare: cf_cost, delta_percent: delta });
438 }
439 }
Billing: AI Gateway's analytics are read with the token that can see them, and a gateway that priced nothing is said440 // The ledger has model cost and the gateway priced none of it: a token
441 // that cannot see AI Gateway reads as no rows, never an error, so this
442 // is not agreement. Said, rather than left as no row at all.
443 if NOT_CLOUDFLARE.contains(&bucket) && cf_cost <= 0.0 && own_cost >= min_cost_micros as f64 && own_cost > 0.0 {
444 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Cost, ours: own_cost, cloudflare: 0.0, delta_percent: None });
445 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily446 if !overhead && cf_cost >= min_cost_micros as f64 && value <= 0.0 {
447 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Leak, ours: value, cloudflare: cf_cost, delta_percent: None });
448 }
449 out
450}
451
Merge branch 'worktree-agent-a633ac0f7f66d419d'452/// What can make AI Gateway's cost differ from what the providers bill,
453/// said for staff: cache tokens (priced by the gateway at its own rates for
454/// them, which may lag the provider's), requests Cloudflare billed itself,
455/// models it has no price for, and runs settled short.
456fn caveat_notes(c: &costs::GatewayCaveats) -> Vec<String> {
457 let mut notes = Vec::new();
458 if c.cache_read_tokens > 0.0 || c.cache_write_tokens > 0.0 {
459 notes.push(format!(
460 "{} prompt-cache read and {} cache write tokens went through it: check its cost against the provider's invoice, since cache reads are billed far below input and writes above it",
461 crate::features::thousands(c.cache_read_tokens.round() as u64),
462 crate::features::thousands(c.cache_write_tokens.round() as u64)
463 ));
464 }
465 if c.wholesale_usd > 0.0 {
466 notes.push(format!(
467 "{} of it Cloudflare billed itself (unified billing): that part is on Cloudflare's bill, not a provider's",
468 dollars(micros(c.wholesale_usd))
469 ));
470 }
471 if !c.unpriced.is_empty() {
472 notes.push(format!("it has no price for {} (tokens used, $0)", c.unpriced.join(", ")));
473 }
474 if c.short_runs > 0 {
475 notes.push(format!("{} runs were settled at no less than the sandbox reported because the gateway could not price all of them", c.short_runs));
476 }
477 notes
478}
479
480/// The models drift's detail: the gateway's total against the ledger's.
481pub(crate) fn models_detail(drift: &Drift, caveats: &costs::GatewayCaveats) -> String {
Billing: AI Gateway's analytics are read with the token that can see them, and a gateway that priced nothing is said482 if drift.cloudflare <= 0.0 {
483 return format!(
484 "Models: the ledger's model cost is {} over the last {DRIFT_DAYS} days and AI Gateway priced nothing, so the two were not compared. Either the gateway's analytics cannot be seen (Cloudflare answers a token without AI Gateway: Read with no rows, not an error; billing reads them with CLOUDFLARE_USAGE_TOKEN, then CLOUDFLARE_BILLING_TOKEN), or model calls went around the gateway.",
485 dollars(drift.ours as i64)
486 );
487 }
Merge branch 'worktree-agent-a633ac0f7f66d419d'488 let lower = drift.ours < drift.cloudflare;
489 let mut detail = format!(
490 "Models: AI Gateway priced g1t's own provider traffic at {} over the last {DRIFT_DAYS} days; the ledger's model cost for the same days is {} ({:+.1}%). {}",
491 dollars(drift.cloudflare as i64),
492 dollars(drift.ours as i64),
493 drift.delta_percent.unwrap_or(0.0),
494 if lower {
495 "Model calls g1t paid for were not charged: runs not yet settled, runs with no session, or calls with no run (the ledger catches up as runs settle; a gap that stays is a leak)."
496 } else {
497 "The ledger counts more than the gateway priced: runs that went to a provider without the gateway, or sandbox reports the gateway could not correct."
498 }
499 );
500 let notes = caveat_notes(caveats);
501 if !notes.is_empty() {
502 detail.push_str(" The gateway's cost may be off: ");
503 detail.push_str(&notes.join("; "));
504 detail.push('.');
505 }
506 detail
507}
508
509/// The unpriced drift's detail.
510pub(crate) fn unpriced_detail(caveats: &costs::GatewayCaveats) -> String {
511 format!(
512 "Models: AI Gateway's cost is not all of what the providers bill over the last {DRIFT_DAYS} days: {}. Runs on a model with no gateway price are charged no less than the sandbox reported; add the model's price to the gateway (or route away from it) so it is charged at cost.",
513 caveat_notes(&costs::GatewayCaveats { cache_read_tokens: 0.0, cache_write_tokens: 0.0, wholesale_usd: 0.0, ..caveats.clone() }).join("; ")
514 )
515}
516
517/// Model usage AI Gateway could not price over the window, as drift on
518/// the models bucket: models with tokens and no cost, or runs settled
519/// short. None when there is none.
520pub(crate) fn unpriced_drift(caveats: &costs::GatewayCaveats) -> Option<(Drift, String)> {
521 if caveats.unpriced.is_empty() && caveats.short_runs == 0 {
522 return None;
523 }
524 let drift = Drift {
525 bucket: NOT_CLOUDFLARE[0].into(),
526 kind: DriftKind::Unpriced,
527 ours: f64::from(caveats.short_runs),
528 cloudflare: caveats.unpriced.len() as f64,
529 delta_percent: None,
530 };
531 Some((drift, unpriced_detail(caveats)))
532}
533
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily534/// When the last `days` in a row (each with enough cost to say something)
535/// were all under the floor: the first of them and the worst margin.
536/// Each item is a day's (day, revenue, cost).
537pub(crate) fn breach(series: &[(String, i64, i64)], floor_percent: f64, days: usize, min_cost_micros: i64) -> Option<(String, f64)> {
538 if days == 0 || series.len() < days {
539 return None;
540 }
541 let tail = &series[series.len() - days..];
542 let mut worst = f64::INFINITY;
543 for (_, revenue, cost) in tail {
544 if *cost < min_cost_micros {
545 return None;
546 }
547 let margin = margin_percent(*revenue, *cost).unwrap_or(-100.0);
548 if margin >= floor_percent {
549 return None;
550 }
551 worst = worst.min(margin);
552 }
553 Some((tail[0].0.clone(), worst))
554}
555
556/// `total` shared out in proportion to `weights`, in whole millionths that
557/// add up to it exactly (largest remainder first). Nothing to share, or no
558/// weight, shares nothing.
559pub(crate) fn attribute(total: i64, weights: &[(String, f64)]) -> Vec<(String, i64)> {
560 let mut merged: BTreeMap<String, f64> = BTreeMap::new();
561 for (key, w) in weights {
562 *merged.entry(key.clone()).or_default() += w.max(0.0);
563 }
564 let sum: f64 = merged.values().sum();
565 if total <= 0 || sum <= 0.0 {
566 return Vec::new();
567 }
568 let mut shares: Vec<(String, i64, f64)> = merged
569 .into_iter()
570 .map(|(key, w)| {
571 let exact = total as f64 * w / sum;
572 (key, exact.floor() as i64, exact - exact.floor())
573 })
574 .collect();
575 let mut left = total - shares.iter().map(|s| s.1).sum::<i64>();
576 let mut order: Vec<usize> = (0..shares.len()).collect();
577 order.sort_by(|a, b| shares[*b].2.total_cmp(&shares[*a].2).then(shares[*a].0.cmp(&shares[*b].0)));
578 for index in order {
579 if left <= 0 {
580 break;
581 }
582 shares[index].1 += 1;
583 left -= 1;
584 }
585 shares.into_iter().filter(|s| s.1 > 0).map(|(key, micros, _)| (key, micros)).collect()
586}
587
588/// Workspaces that cost g1t more than `factor` times what they paid, with
589/// at least `floor_micros` of cost: each (workspace, cost, revenue), the
590/// biggest gap first.
Models' margin read -14%: usage nothing paid for is valued at price, not $0591/// What a day's usage was worth at price. g1t's own workspaces are valued
592/// at price. So is usage nothing paid for, neither charged nor drawn from
593/// the plan, a trial, a pool or a gift (a free period): it was given away at
594/// its price, not sold for nothing. Anything paid keeps what it was paid, so
595/// a discount still shows as one.
596pub(crate) fn usage_value(internal: bool, cost: i64, paid: i64, margin_percent: u32) -> i64 {
597 if internal || (paid == 0 && cost > 0) {
598 return crate::credits::with_margin(cost, margin_percent);
599 }
600 paid
601}
602
Margin alerts measure what is sold, and say dollars when a percentage would mislead603/// What the overall alert says: the money as money, and a percentage only
604/// while there is enough coming in for one to mean something (a few cents
605/// against dollars of cost reads as -8000%).
606pub(crate) fn overall_detail(took: i64, spent: i64, days: usize, floor: f64, worst: f64) -> String {
607 if took < 1_000_000 * days as i64 {
608 return format!(
609 "All of g1t, comped workspaces left out: took in {} against {} of Cloudflare's bill over {days} days.",
610 dollars(took),
611 dollars(spent)
612 );
613 }
614 format!("All of g1t, comped workspaces left out: money in against Cloudflare's bill under {floor:.0}% for {days} days running, as low as {worst:.1}%.")
615}
616
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily617pub(crate) fn anomalies(rows: &[(String, i64, i64)], factor: f64, floor_micros: i64) -> Vec<(String, i64, i64)> {
618 let mut out: Vec<(String, i64, i64)> = rows
619 .iter()
620 .filter(|(_, cost, revenue)| *cost >= floor_micros && *cost as f64 > *revenue as f64 * factor)
621 .cloned()
622 .collect();
623 out.sort_by(|a, b| (b.1 - b.2).cmp(&(a.1 - a.2)).then(a.0.cmp(&b.0)));
624 out
625}
626
627/// Cloudflare's marginal rate for one of its units: the median over the
628/// charged days of cost over quantity, in dollars. None while the included
629/// amounts still cover it. Each item is a day's (quantity, cost).
630pub(crate) fn billed_rate(days: &[(f64, f64)]) -> Option<f64> {
631 let mut rates: Vec<f64> = days.iter().filter(|(q, c)| *q > 0.0 && *c > 0.0).map(|(q, c)| c / q).collect();
632 if rates.is_empty() {
633 return None;
634 }
635 rates.sort_by(f64::total_cmp);
636 Some(rates[rates.len() / 2])
637}
638
639/// What one of g1t's units costs, from Cloudflare's rate per its own unit
640/// and how many of Cloudflare's units each of g1t's took: if Cloudflare
641/// counts three operations for every git operation g1t counts, a git
642/// operation costs three of Cloudflare's. None without enough of g1t's
643/// units to say.
644pub(crate) fn derived_unit_cost(rate_per_cf_unit: f64, cf_units: f64, own_units: f64) -> Option<f64> {
645 (own_units >= MIN_UNITS && cf_units > 0.0 && rate_per_cf_unit > 0.0).then(|| rate_per_cf_unit * cf_units / own_units)
646}
647
648/// How many units a price is per: `1,000 operations` → 1,000, `million
649/// requests` → 1,000,000, `second` → 1.
650pub(crate) fn unit_size(unit: &str) -> f64 {
651 let first = unit.split_whitespace().next().unwrap_or_default().replace(',', "");
652 match first.as_str() {
653 "million" => 1_000_000.0,
654 "thousand" => 1_000.0,
655 n => n.parse().unwrap_or(1.0),
656 }
657}
658
659fn day_before(day: &str, days: u64) -> String {
660 let ms = g1t_contracts::time::parse_rfc3339(&format!("{day}T00:00:00Z")).unwrap_or(0);
661 rfc3339(ms.saturating_sub(days * DAY_MS))[..10].to_owned()
662}
663
664/// Dollars to the cent from a dollar up, finer below: `$17.02`, `$0.063`.
665fn dollars(micros: i64) -> String {
666 if micros.abs() >= 1_000_000 {
667 let cents = (micros as f64 / 10_000.0).round() as i64;
668 format!("{}${}.{:02}", if cents < 0 { "-" } else { "" }, cents.abs() / 100, cents.abs() % 100)
669 } else {
670 crate::features::dollars(micros)
671 }
672}
673
674/// The days a plan payment is spread over.
675const PLAN_DAYS: u64 = 30;
676
677/// `micros` paid on `day` spread evenly over `days` days from it, in
678/// whole micros that add up to it (the first days take the remainder).
679pub(crate) fn spread(day: &str, micros: i64, days: u64) -> Vec<(String, i64)> {
680 if micros <= 0 || days == 0 {
681 return Vec::new();
682 }
683 let start = g1t_contracts::time::parse_rfc3339(&format!("{}T00:00:00Z", &day[..10.min(day.len())])).unwrap_or(0);
684 let each = micros / days as i64;
685 let rest = micros % days as i64;
686 (0..days)
687 .map(|n| (rfc3339(start + n * DAY_MS)[..10].to_owned(), each + i64::from((n as i64) < rest)))
688 .collect()
689}
690
691// ---------------------------------------------------------------------
692// The daily run, and what sudo reads.
693// ---------------------------------------------------------------------
694
695#[derive(Serialize)]
696struct Mail<'a> {
697 to: &'a str,
698 from: &'a str,
699 subject: &'a str,
700 text: String,
701 html: String,
702}
703
704fn escape(text: &str) -> String {
705 text.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;").replace('"', "&quot;")
706}
707
708/// Emails staff through Cloudflare Email Sending, the `EMAIL` binding.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays709pub(crate) async fn email_staff(env: &Env, to: &str, subject: &str, lines: &[String]) -> Result<()> {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily710 let link = "https://sudo.g1t.sh/costs";
711 let text = format!("{}\n\nCosts & margin: {link}\n\nSent by g1t-billing's margin guard (COSTS_ALERT_EMAIL).\n", lines.join("\n\n"));
712 let mut html = String::from("<div style=\"font-family:system-ui,sans-serif;max-width:560px;margin:0 auto;padding:24px 16px;color:#16150f\">");
713 for line in lines {
714 html.push_str(&format!("<p style=\"font-size:15px;line-height:1.6\">{}</p>", escape(line)));
715 }
716 html.push_str(&format!(
717 "<p><a href=\"{link}\">Open Costs &amp; margin in sudo</a></p><p style=\"font-size:13px;color:#6e6a5e\">Sent by g1t-billing's margin guard (COSTS_ALERT_EMAIL).</p></div>"
718 ));
719 let mail = Mail { to, from: "g1t <noreply@g1t.sh>", subject, text, html };
720 let binding = g1t_kit::js::binding(env, "EMAIL")?;
721 g1t_kit::js::call(&binding, "send", &[g1t_kit::js::to_js(&mail)?]).await?;
722 Ok(())
723}
724
725#[derive(Deserialize)]
726struct AlertRow {
727 id: String,
728 kind: String,
729 subject: String,
730 detail: String,
731 since: String,
732 opened_at: String,
733 emailed_at: Option<String>,
734}
735
736impl From<AlertRow> for MarginAlert {
737 fn from(r: AlertRow) -> Self {
738 MarginAlert { id: r.id, kind: r.kind, subject: r.subject, detail: r.detail, since: r.since, opened_at: r.opened_at, emailed_at: r.emailed_at }
739 }
740}
741
742#[derive(Deserialize)]
743struct MarginRow {
744 day: String,
745 bucket: String,
746 cf_cost_micros: i64,
747 own_cost_micros: i64,
748 value_micros: i64,
749 cash_micros: i64,
750 cf_quantity: f64,
751 own_quantity: f64,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it752 #[serde(default)]
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running753 given_comped_micros: Option<i64>,
754 #[serde(default)]
755 given_free_micros: Option<i64>,
756 #[serde(default)]
757 given_trial_micros: Option<i64>,
758 #[serde(default)]
759 given_pool_micros: Option<i64>,
Merge branch 'worktree-agent-a633ac0f7f66d419d'760 #[serde(default)]
761 given_discount_micros: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily762}
763
764impl From<MarginRow> for ProductDay {
765 fn from(r: MarginRow) -> Self {
766 ProductDay {
767 day: r.day,
768 bucket: r.bucket,
769 cf_cost_micros: r.cf_cost_micros,
770 own_cost_micros: r.own_cost_micros,
771 value_micros: r.value_micros,
772 cash_micros: r.cash_micros,
773 cf_quantity: r.cf_quantity,
774 own_quantity: r.own_quantity,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running775 given: Given {
776 comped: r.given_comped_micros.unwrap_or(0),
777 free: r.given_free_micros.unwrap_or(0),
778 trial: r.given_trial_micros.unwrap_or(0),
779 pool: r.given_pool_micros.unwrap_or(0),
Merge branch 'worktree-agent-a633ac0f7f66d419d'780 discount: r.given_discount_micros.unwrap_or(0),
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running781 },
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily782 }
783 }
784}
785
786impl Billing {
787 /// The day's work: read Cloudflare's bill and g1t's own counts,
788 /// reconcile, look for drift, measure unit costs, apply prices whose
789 /// day has come, and raise or clear alerts.
790 pub(crate) async fn costs_daily(&self, env: &Env, keeper: &crate::keeper::Keeper) -> Result<CostsRun> {
791 let mut run = CostsRun::default();
792 let (since, until) = match self.read_cloudflare(keeper, &mut run.problems).await? {
793 Some((since, until, lines)) => {
794 run.lines = lines;
795 (since, until)
796 }
797 // Without the bill, still reconcile what g1t knows itself, over
798 // the same days the bill would be read for.
799 None => {
800 #[derive(Deserialize)]
801 struct Last {
802 day: Option<String>,
803 }
804 let last = self.db.prepare("SELECT MAX(day) AS day FROM margin_days").first::<Last>(None).await?.and_then(|l| l.day);
805 costs::window(last.as_deref(), now_ms())
806 }
807 };
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing808 // Not a problem for the run: the last read, or the estimate, stays.
809 if keeper.can_read_bill()
810 && let Err(error) = self.read_subscriptions(keeper).await
811 {
812 worker::console_error!("Cloudflare's subscriptions were not read: {error}");
813 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily814 if let Err(error) = self.count_own(&since, &until).await {
815 run.problems.push(format!("g1t's own counts could not be read: {error}"));
816 }
817 self.snapshot_pending(&until).await?;
Models' margin read -14%: usage nothing paid for is valued at price, not $0818 // Reconciled over the whole window sudo shows, not only the days the
819 // bill was read for: it reads only what is already kept, so a change
820 // in how a day is valued reaches every day shown at the next run.
821 let window = day_before(&until, costs::BACKFILL_DAYS - 1);
822 let reconcile_from = if window < since { window } else { since.clone() };
823 run.days = self.reconcile_range(&reconcile_from, &until).await?;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily824 let drift = self.find_drift(&until).await?;
825 run.proposals = self.measure_units(&until).await?;
826 self.apply_due_versions().await?;
827 run.alerts = self.raise_alerts(env, &until, &drift).await?;
828 if let Some(identity) = &self.identity
829 && let Err(error) = self.tell_owners_of_rises(identity).await
830 {
831 run.problems.push(format!("owners could not be told of a price rise: {error}"));
832 }
833 for problem in &run.problems {
834 worker::console_warn!("costs: {problem}");
835 }
836 Ok(run)
837 }
838
839 /// What each month-end source had come to by the end of `day`.
840 async fn snapshot_pending(&self, day: &str) -> Result<()> {
841 self.db
842 .prepare(
843 "INSERT INTO pending_days (day, workspace, source, cost_micros, charge_micros)
844 SELECT ?1, workspace, source, COALESCE(cost_micros, 0), COALESCE(charge_micros, 0) FROM pending_usage WHERE month = ?2
845 ON CONFLICT (day, workspace, source) DO UPDATE SET cost_micros = excluded.cost_micros, charge_micros = excluded.charge_micros",
846 )
847 .bind(&[day.into(), day[..7].into()])?
848 .run()
849 .await?;
850 Ok(())
851 }
852
853 /// What customers were charged on the days, by workspace and key.
854 async fn usage_rows(&self, since: &str, until: &str) -> Result<Vec<UsageRow>> {
855 #[derive(Deserialize)]
856 struct Row {
857 day: String,
858 workspace: String,
859 key: String,
860 internal: i64,
861 own_provider: i64,
862 cash: Option<i64>,
863 drawn: Option<i64>,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running864 trial: Option<i64>,
865 oss: Option<i64>,
866 covered: Option<i64>,
Merge branch 'worktree-agent-a633ac0f7f66d419d'867 discount: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily868 cost: Option<i64>,
869 }
870 let charged_here = crate::storage::CHARGED_HERE.iter().map(|s| format!("'{s}'")).collect::<Vec<_>>().join(", ");
871 let end = format!("{until}T23:59:59.999Z");
872 let rows = self
873 .db
874 .prepare(format!(
875 "SELECT substr(created_at, 1, 10) AS day, workspace,
876 CASE WHEN task = 'deployments' AND reference LIKE 'deploy/%' THEN 'builds' ELSE COALESCE(task, 'other') END AS key,
877 CASE WHEN workspace IN ({internal}) THEN 1 ELSE 0 END AS internal,
878 CASE WHEN billed_to = 'workspace' THEN 1 ELSE 0 END AS own_provider,
879 -SUM(amount_micros) AS cash,
880 SUM(COALESCE(credit_micros, 0) + COALESCE(trial_micros, 0) + COALESCE(oss_micros, 0) + COALESCE(given_micros, 0)) AS drawn,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running881 SUM(COALESCE(trial_micros, 0)) AS trial,
882 SUM(COALESCE(oss_micros, 0)) AS oss,
883 SUM(COALESCE(given_micros, 0)) AS covered,
Merge branch 'worktree-agent-a633ac0f7f66d419d'884 SUM(COALESCE(discount_micros, 0)) AS discount,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily885 SUM(COALESCE(cost_micros, 0)) AS cost
886 FROM ledger
887 WHERE kind = 'usage' AND created_at >= ?1 AND created_at <= ?2 AND COALESCE(task, '') NOT IN ({charged_here})
888 GROUP BY 1, 2, 3, 4, 5",
889 internal = crate::sales::INTERNAL_SQL
890 ))
891 .bind(&[since.into(), end.as_str().into()])?
892 .all()
893 .await?
894 .results::<Row>()?;
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it895 let mut internal = BTreeSet::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily896 let mut out: Vec<UsageRow> = rows
897 .into_iter()
898 .map(|r| {
899 // A workspace's own model provider was paid there: no cost
900 // to g1t. g1t's own workspaces are valued at price.
901 let cost = if r.own_provider == 1 { 0 } else { r.cost.unwrap_or(0) };
902 let cash = r.cash.unwrap_or(0);
Merge branch 'worktree-agent-a633ac0f7f66d419d'903 // A discount took its part below cost plus the margin: it is
904 // valued at price and that part counted as given, so a
905 // discounted sale never reads as margin lost.
906 let discount = r.discount.unwrap_or(0).max(0);
907 let paid = cash + r.drawn.unwrap_or(0) + discount;
Models' margin read -14%: usage nothing paid for is valued at price, not $0908 let value = usage_value(r.internal == 1, cost, paid, self.margin_percent);
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running909 let given = if r.internal == 1 {
910 Given { comped: value, ..Given::default() }
911 } else if paid == 0 && cost > 0 {
912 Given { free: value, ..Given::default() }
913 } else {
Merge branch 'worktree-agent-a633ac0f7f66d419d'914 Given { free: r.covered.unwrap_or(0), trial: r.trial.unwrap_or(0), pool: r.oss.unwrap_or(0), comped: 0, discount }
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running915 };
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it916 if r.internal == 1 {
917 internal.insert(r.workspace.clone());
918 }
919 UsageRow { day: r.day, workspace: r.workspace, key: r.key, value, cash, cost, given }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily920 })
921 .collect();
922 // Month-end sources, from their daily snapshots.
923 #[derive(Deserialize)]
924 struct Snap {
925 day: String,
926 workspace: String,
927 source: String,
928 cost_micros: i64,
929 charge_micros: i64,
930 }
931 let snaps = self
932 .db
933 .prepare("SELECT day, workspace, source, cost_micros, charge_micros FROM pending_days WHERE day >= ?1 AND day <= ?2")
934 .bind(&[day_before(since, 1).into(), until.into()])?
935 .all()
936 .await?
937 .results::<Snap>()?
938 .into_iter()
939 .filter(|s| crate::storage::CHARGED_HERE.contains(&s.source.as_str()) || s.source == "domains")
940 .map(|s| (s.day, s.workspace, s.source, s.cost_micros, s.charge_micros))
941 .collect::<Vec<_>>();
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it942 out.extend(pending_deltas(&snaps).into_iter().filter(|u| u.day.as_str() >= since).map(|mut u| {
943 if internal.contains(&u.workspace) {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running944 u.given = Given { comped: u.value, ..Given::default() };
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it945 }
946 u
947 }));
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily948 // The plan's price, spread over the 30 days it pays for, so a month's
949 // payment does not read as one very good day and 29 bad ones.
950 #[derive(Deserialize)]
951 struct Plan {
952 day: String,
953 workspace: String,
954 micros: Option<i64>,
955 }
956 let plans = self
957 .db
958 .prepare(
959 "SELECT substr(paid_at, 1, 10) AS day, workspace, SUM(amount_micros) AS micros FROM plan_payments
960 WHERE paid_at >= ?1 AND paid_at <= ?2 GROUP BY 1, 2",
961 )
962 .bind(&[day_before(since, PLAN_DAYS - 1).into(), end.as_str().into()])?
963 .all()
964 .await?
965 .results::<Plan>()?;
966 for p in plans {
967 for (day, micros) in spread(&p.day, p.micros.unwrap_or(0), PLAN_DAYS) {
968 if day.as_str() >= since && day.as_str() <= until {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running969 out.push(UsageRow { day, workspace: p.workspace.clone(), key: "plan".into(), value: micros, cash: micros, cost: 0, given: Given::default() });
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily970 }
971 }
972 }
973 Ok(out)
974 }
975
976 /// Reconciles the days and writes `margin_days` and `workspace_costs`.
977 async fn reconcile_range(&self, since: &str, until: &str) -> Result<u32> {
978 let rules = self.rules().await?;
979 #[derive(Deserialize)]
980 struct Map {
981 key: String,
982 bucket: String,
983 }
984 let revenue_map: BTreeMap<String, String> = self
985 .db
986 .prepare("SELECT key, bucket FROM revenue_map")
987 .all()
988 .await?
989 .results::<Map>()?
990 .into_iter()
991 .map(|m| (m.key, m.bucket))
992 .collect();
993 let lines = self
994 .db
995 .prepare("SELECT day, source, product, meter, quantity, cost_usd FROM cost_lines WHERE day >= ?1 AND day <= ?2")
996 .bind(&[since.into(), until.into()])?
997 .all()
998 .await?
999 .results::<LineRow>()?;
1000 let own = self
1001 .db
1002 .prepare("SELECT day, meter, workspace, quantity FROM own_counts WHERE day >= ?1 AND day <= ?2")
1003 .bind(&[since.into(), until.into()])?
1004 .all()
1005 .await?
1006 .results::<OwnRow>()?;
1007 let usage = self.usage_rows(since, until).await?;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1008 #[derive(Deserialize)]
1009 struct Internal {
1010 workspace: String,
1011 }
1012 let internal: BTreeSet<String> = self
1013 .db
1014 .prepare(format!("WITH i(workspace) AS ({}) SELECT DISTINCT workspace FROM i", crate::sales::INTERNAL_SQL))
1015 .all()
1016 .await?
1017 .results::<Internal>()?
1018 .into_iter()
1019 .map(|i| i.workspace)
1020 .collect();
1021 let (days, workspaces) = fold(&rules, &revenue_map, &lines, &own, &usage, &internal);
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1022 let now = rfc3339(now_ms());
1023 self.db
1024 .batch(vec![
1025 self.db.prepare("DELETE FROM margin_days WHERE day >= ?1 AND day <= ?2").bind(&[since.into(), until.into()])?,
1026 self.db.prepare("DELETE FROM workspace_costs WHERE day >= ?1 AND day <= ?2").bind(&[since.into(), until.into()])?,
1027 ])
1028 .await?;
1029 for chunk in days.chunks(50) {
1030 let mut statements = Vec::with_capacity(chunk.len());
1031 for d in chunk {
1032 statements.push(
1033 self.db
1034 .prepare(
Merge branch 'worktree-agent-a633ac0f7f66d419d'1035 "INSERT OR REPLACE INTO margin_days (day, bucket, cf_cost_micros, own_cost_micros, value_micros, cash_micros, cf_quantity, own_quantity, given_micros, given_comped_micros, given_free_micros, given_trial_micros, given_pool_micros, given_discount_micros, computed_at)
1036 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1037 )
1038 .bind(&[
1039 d.day.as_str().into(),
1040 d.bucket.as_str().into(),
1041 (d.cf_cost_micros as f64).into(),
1042 (d.own_cost_micros as f64).into(),
1043 (d.value_micros as f64).into(),
1044 (d.cash_micros as f64).into(),
1045 d.cf_quantity.into(),
1046 d.own_quantity.into(),
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1047 (d.given.total() as f64).into(),
1048 (d.given.comped as f64).into(),
1049 (d.given.free as f64).into(),
1050 (d.given.trial as f64).into(),
1051 (d.given.pool as f64).into(),
Merge branch 'worktree-agent-a633ac0f7f66d419d'1052 (d.given.discount as f64).into(),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1053 now.as_str().into(),
1054 ])?,
1055 );
1056 }
1057 self.db.batch(statements).await?;
1058 }
1059 for chunk in workspaces.chunks(50) {
1060 let mut statements = Vec::with_capacity(chunk.len());
1061 for w in chunk {
1062 statements.push(
1063 self.db
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1064 .prepare("INSERT OR REPLACE INTO workspace_costs (day, workspace, bucket, cost_micros, revenue_micros, value_micros, given_micros) VALUES (?, ?, ?, ?, ?, ?, ?)")
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1065 .bind(&[
1066 w.day.as_str().into(),
1067 w.workspace.as_str().into(),
1068 w.bucket.as_str().into(),
1069 (w.cost as f64).into(),
1070 (w.revenue as f64).into(),
Margin alerts measure what is sold, and say dollars when a percentage would mislead1071 (w.value as f64).into(),
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1072 (w.given.total() as f64).into(),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1073 ])?,
1074 );
1075 }
1076 self.db.batch(statements).await?;
1077 }
1078 Ok(costs::days_between(since, until).len() as u32)
1079 }
1080
1081 async fn margin_days(&self, since: &str, until: &str) -> Result<Vec<ProductDay>> {
1082 Ok(self
1083 .db
1084 .prepare("SELECT * FROM margin_days WHERE day >= ?1 AND day <= ?2 ORDER BY day, bucket")
1085 .bind(&[since.into(), until.into()])?
1086 .all()
1087 .await?
1088 .results::<MarginRow>()?
1089 .into_iter()
1090 .map(ProductDay::from)
1091 .collect())
1092 }
1093
Merge branch 'worktree-agent-a633ac0f7f66d419d'1094 /// What AI Gateway's lines over the days, and the runs settled in them,
1095 /// say about whether its cost is what the providers bill.
1096 async fn gateway_caveats(&self, since: &str, until: &str) -> Result<costs::GatewayCaveats> {
1097 #[derive(Deserialize)]
1098 struct Line {
1099 meter: String,
1100 quantity: f64,
1101 cost_usd: f64,
1102 }
1103 let lines: Vec<(String, f64, f64)> = self
1104 .db
1105 .prepare("SELECT meter, quantity, cost_usd FROM cost_lines WHERE source = ?1 AND day >= ?2 AND day <= ?3")
1106 .bind(&[costs::SOURCE_GATEWAY.into(), since.into(), until.into()])?
1107 .all()
1108 .await?
1109 .results::<Line>()?
1110 .into_iter()
1111 .map(|l| (l.meter, l.quantity, l.cost_usd))
1112 .collect();
1113 let mut caveats = costs::gateway_caveats(&lines);
1114 #[derive(Deserialize)]
1115 struct Short {
1116 n: Option<f64>,
1117 }
1118 caveats.short_runs = self
1119 .db
1120 .prepare("SELECT COUNT(*) AS n FROM runs WHERE gateway_note IS NOT NULL AND settled_at >= ?1 AND settled_at <= ?2")
1121 .bind(&[since.into(), format!("{until}T23:59:59.999Z").into()])?
1122 .first::<Short>(None)
1123 .await?
1124 .and_then(|s| s.n)
1125 .unwrap_or(0.0) as u32;
1126 Ok(caveats)
1127 }
1128
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1129 /// Drift over the last week, written to `cost_drift` (replacing the
1130 /// last run's), with unmapped Cloudflare meters as leaks.
1131 async fn find_drift(&self, until: &str) -> Result<Vec<(Drift, String)>> {
1132 let since = day_before(until, DRIFT_DAYS - 1);
1133 let settings = self.cost_settings().await?;
1134 let rules = self.rules().await?;
1135 let days = self.margin_days(&since, until).await?;
1136 let mut by: BTreeMap<String, Vec<ProductDay>> = BTreeMap::new();
1137 for d in days {
1138 by.entry(d.bucket.clone()).or_default().push(d);
1139 }
Merge branch 'worktree-agent-a633ac0f7f66d419d'1140 let caveats = self.gateway_caveats(&since, until).await?;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1141 let mut found = Vec::new();
Merge branch 'worktree-agent-a633ac0f7f66d419d'1142 if let Some(drift) = unpriced_drift(&caveats) {
1143 found.push(drift);
1144 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1145 for (bucket, days) in &by {
1146 let bucket_rules: Vec<&Rule> = rules.iter().filter(|r| &r.bucket == bucket).collect();
1147 let threshold = bucket_rules.iter().map(|r| r.drift_percent).fold(f64::INFINITY, f64::min);
1148 let threshold = if threshold.is_finite() { threshold } else { 10.0 };
1149 let counted = bucket_rules.iter().any(|r| r.own_meter.is_some());
1150 for drift in drifts(bucket, days, threshold, counted, settings.min_daily_cost_micros) {
1151 let title = costs::bucket_title(bucket);
1152 let detail = match drift.kind {
Merge branch 'worktree-agent-a633ac0f7f66d419d'1153 DriftKind::Cost if NOT_CLOUDFLARE.contains(&bucket.as_str()) => models_detail(&drift, &caveats),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1154 DriftKind::Count => format!(
One operation mapping, owned by repos; billing reads it instead of keeping its own1155 "{title}: g1t counted {}, Cloudflare {} over the last {DRIFT_DAYS} days ({:+.1}%). Customers are charged for what g1t counts; check what Cloudflare counts as a unit and change the repos service's operation_mapping (set_operation_mapping).",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1156 crate::features::thousands(drift.ours.max(0.0).round() as u64),
1157 crate::features::thousands(drift.cloudflare.max(0.0).round() as u64),
1158 drift.delta_percent.unwrap_or(0.0)
1159 ),
1160 DriftKind::Cost => format!(
1161 "{title}: Cloudflare charged {} over the last {DRIFT_DAYS} days; the price book's cost of the same usage is {} ({:+.1}%). A price may be stale: see the proposals.",
1162 dollars(drift.cloudflare as i64),
1163 dollars(drift.ours as i64),
1164 drift.delta_percent.unwrap_or(0.0)
1165 ),
1166 DriftKind::Leak if bucket == UNMAPPED => {
1167 format!("Cloudflare charged {} for meters no mapping claims. Map them on Costs & margin.", dollars(drift.cloudflare as i64))
1168 }
Merge branch 'worktree-agent-a633ac0f7f66d419d'1169 DriftKind::Leak if NOT_CLOUDFLARE.contains(&bucket.as_str()) => format!(
1170 "{title}: AI Gateway priced g1t's own provider traffic at {} over the last {DRIFT_DAYS} days and the ledger has no model charge for it, not even a comped or free one: model calls with no billing run behind them (a run started without a ticket, or something else using g1t's gateway).",
1171 dollars(drift.cloudflare as i64)
1172 ),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1173 DriftKind::Leak => format!(
1174 "{title}: Cloudflare charged {} over the last {DRIFT_DAYS} days and customers were charged nothing for it.",
1175 dollars(drift.cloudflare as i64)
1176 ),
Merge branch 'worktree-agent-a633ac0f7f66d419d'1177 // Raised from the gateway's lines, not per bucket.
1178 DriftKind::Unpriced => unpriced_detail(&caveats),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1179 };
1180 found.push((drift, detail));
1181 }
1182 }
1183 let now = rfc3339(now_ms());
1184 let mut statements = vec![self.db.prepare("DELETE FROM cost_drift")];
1185 for (drift, detail) in &found {
1186 statements.push(
1187 self.db
1188 .prepare("INSERT OR REPLACE INTO cost_drift (bucket, kind, ours, cloudflare, delta_percent, detail, found_at) VALUES (?, ?, ?, ?, ?, ?, ?)")
1189 .bind(&[
1190 drift.bucket.as_str().into(),
1191 drift.kind.as_str().into(),
1192 drift.ours.into(),
1193 drift.cloudflare.into(),
1194 drift.delta_percent.map_or(JsValue::NULL, JsValue::from),
1195 detail.as_str().into(),
1196 now.as_str().into(),
1197 ])?,
1198 );
1199 }
1200 self.db.batch(statements).await?;
1201 Ok(found)
1202 }
1203
1204 /// Unit costs from the bill for mappings that scale to g1t's own count
1205 /// (git operations), proposed to the price book.
1206 async fn measure_units(&self, until: &str) -> Result<u32> {
1207 #[derive(Deserialize)]
1208 struct Scaled {
1209 product: String,
1210 meter: String,
1211 price_meter: String,
1212 own_meter: String,
1213 unit: Option<String>,
1214 }
1215 let scaled = self
1216 .db
1217 .prepare(
1218 "SELECT m.product, m.meter, m.price_meter, m.own_meter, p.unit FROM cost_map m LEFT JOIN prices p ON p.meter = m.price_meter
1219 WHERE m.scale_to_own = 1 AND m.price_meter IS NOT NULL AND m.own_meter IS NOT NULL",
1220 )
1221 .all()
1222 .await?
1223 .results::<Scaled>()?;
1224 let since = day_before(until, MEASURE_DAYS - 1);
1225 let rules = self.rules().await?;
1226 let mut proposed = 0;
1227 for s in scaled {
1228 #[derive(Deserialize)]
1229 struct Day {
1230 product: String,
1231 meter: String,
1232 quantity: f64,
1233 cost_usd: f64,
1234 }
1235 let lines = self
1236 .db
1237 .prepare("SELECT product, meter, quantity, cost_usd FROM cost_lines WHERE source = ?1 AND product = ?2 AND day >= ?3 AND day <= ?4")
1238 .bind(&[SOURCE_BILLABLE.into(), s.product.as_str().into(), since.as_str().into(), until.into()])?
1239 .all()
1240 .await?
1241 .results::<Day>()?;
1242 // Only the lines this very mapping claims.
1243 let mine: Vec<(f64, f64)> = lines
1244 .iter()
1245 .filter(|l| costs::classify(&rules, &l.product, &l.meter).is_some_and(|r| r.product == s.product && r.meter == s.meter))
1246 .map(|l| (l.quantity, l.cost_usd))
1247 .collect();
1248 let Some(rate) = billed_rate(&mine) else { continue };
1249 let cf_units: f64 = mine.iter().map(|(q, _)| q).sum();
1250 #[derive(Deserialize)]
1251 struct Own {
1252 total: Option<f64>,
1253 }
1254 let own_units = self
1255 .db
1256 .prepare("SELECT SUM(quantity) AS total FROM own_counts WHERE meter = ?1 AND day >= ?2 AND day <= ?3")
1257 .bind(&[s.own_meter.as_str().into(), since.as_str().into(), until.into()])?
1258 .first::<Own>(None)
1259 .await?
1260 .and_then(|o| o.total)
1261 .unwrap_or(0.0);
1262 let Some(per_unit) = derived_unit_cost(rate, cf_units, own_units) else { continue };
1263 let size = unit_size(s.unit.as_deref().unwrap_or("1"));
1264 let measured = per_unit * size * 1_000_000.0;
1265 let reason = format!(
1266 "Cloudflare billed ${:.4} per 1,000 of its units and counted {:.2} of them for each one g1t counted over the last {MEASURE_DAYS} days ({} against {})",
1267 rate * 1000.0,
1268 cf_units / own_units,
1269 crate::features::thousands(cf_units.round() as u64),
1270 crate::features::thousands(own_units.round() as u64)
1271 );
1272 if self.propose(&s.price_meter, measured, &reason, "reconciler").await?.is_some() {
1273 proposed += 1;
1274 }
1275 }
1276 Ok(proposed)
1277 }
1278
1279 /// Opens, updates and closes margin alerts, and emails staff about new
1280 /// ones (and open ones each week).
1281 async fn raise_alerts(&self, env: &Env, until: &str, drift: &[(Drift, String)]) -> Result<u32> {
1282 let settings = self.cost_settings().await?;
1283 let since = day_before(until, u64::from(settings.alert_days.max(1)) - 1);
1284 let days = self.margin_days(&since, until).await?;
1285 let mut conditions: Vec<(String, String, String, String)> = Vec::new();
1286 // Each product under the floor.
1287 let mut by: BTreeMap<String, Vec<(String, i64, i64)>> = BTreeMap::new();
1288 let mut all: BTreeMap<String, (i64, i64)> = BTreeMap::new();
1289 for d in &days {
1290 let overall = all.entry(d.day.clone()).or_default();
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1291 // What g1t gave away (comped workspaces, free periods, the
1292 // trial and the pools) is a budget it chose to spend, watched on
1293 // its own (budget.rs): not part of whether what is sold pays.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1294 overall.0 += d.cash_micros;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1295 overall.1 += (d.cost() - d.given.total()).max(0);
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1296 if !OVERHEAD.contains(&d.bucket.as_str()) && d.bucket != UNMAPPED {
1297 by.entry(d.bucket.clone()).or_default().push((d.day.clone(), d.value_micros, d.cost()));
1298 }
1299 }
1300 let floor = settings.margin_floor_percent;
1301 let n = settings.alert_days as usize;
1302 for (bucket, series) in &by {
1303 if let Some((from, worst)) = breach(series, floor, n, settings.min_daily_cost_micros) {
1304 conditions.push((
1305 "margin".into(),
1306 bucket.clone(),
1307 format!("{}: margin under {floor:.0}% for {n} days running, as low as {worst:.1}%.", costs::bucket_title(bucket)),
1308 from,
1309 ));
Margin alerts measure what is sold, and say dollars when a percentage would mislead1310 }
1311 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1312 let series: Vec<(String, i64, i64)> = all.into_iter().map(|(day, (revenue, cost))| (day, revenue, cost)).collect();
1313 if let Some((from, worst)) = breach(&series, floor, n, settings.min_daily_cost_micros) {
Margin alerts measure what is sold, and say dollars when a percentage would mislead1314 let tail = &series[series.len().saturating_sub(n)..];
1315 let (took, spent) = tail.iter().fold((0i64, 0i64), |(r, c), (_, revenue, cost)| (r + revenue, c + cost));
1316 conditions.push(("overall".into(), "g1t".into(), overall_detail(took, spent, n, floor, worst), from));
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1317 }
1318 for (d, detail) in drift {
1319 let kind = if d.kind == DriftKind::Leak { "leak" } else { "drift" };
1320 conditions.push((kind.into(), format!("{}:{}", d.bucket, d.kind.as_str()), detail.clone(), until.to_owned()));
1321 }
1322 // Workspaces costing more than they pay.
1323 for (workspace, cost, revenue) in self.workspace_anomalies(until, &settings).await? {
1324 conditions.push((
1325 "workspace".into(),
1326 workspace.clone(),
Margin alerts measure what is sold, and say dollars when a percentage would mislead1327 format!(
1328 "{workspace} cost g1t {} on Cloudflare over {ANOMALY_DAYS} days, and its usage was priced at {}: its prices are below cost.",
1329 dollars(cost),
1330 dollars(revenue)
1331 ),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1332 day_before(until, ANOMALY_DAYS - 1),
1333 ));
1334 }
1335
1336 let open = self
1337 .db
1338 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL")
1339 .all()
1340 .await?
1341 .results::<AlertRow>()?;
1342 let now = now_ms();
1343 let stamp = rfc3339(now);
1344 let mut to_email: Vec<String> = Vec::new();
1345 let mut kept: BTreeSet<String> = BTreeSet::new();
1346 for (kind, subject, detail, from) in &conditions {
1347 match open.iter().find(|a| &a.kind == kind && &a.subject == subject) {
1348 Some(alert) => {
1349 kept.insert(alert.id.clone());
1350 self.db
1351 .prepare("UPDATE margin_alerts SET detail = ? WHERE id = ?")
1352 .bind(&[detail.as_str().into(), alert.id.as_str().into()])?
1353 .run()
1354 .await?;
1355 let stale = alert
1356 .emailed_at
1357 .as_deref()
1358 .and_then(g1t_contracts::time::parse_rfc3339)
1359 .is_none_or(|at| now.saturating_sub(at) >= REMIND_MS);
1360 if stale && kind != "workspace" {
1361 to_email.push(format!("Still open: {detail}"));
1362 kept.insert(format!("email:{}", alert.id));
1363 }
1364 }
1365 None => {
1366 let id = new_id("mal", now);
1367 self.db
1368 .prepare("INSERT INTO margin_alerts (id, kind, subject, detail, since, opened_at) VALUES (?, ?, ?, ?, ?, ?)")
1369 .bind(&[id.as_str().into(), kind.as_str().into(), subject.as_str().into(), detail.as_str().into(), from.as_str().into(), stamp.as_str().into()])?
1370 .run()
1371 .await?;
1372 kept.insert(id.clone());
Margin alerts measure what is sold, and say dollars when a percentage would mislead1373 // A workspace's is for Reach out, not the inbox.
1374 if kind != "workspace" {
1375 to_email.push(detail.clone());
1376 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1377 kept.insert(format!("email:{id}"));
1378 }
1379 }
1380 }
1381 for alert in &open {
1382 if !kept.contains(&alert.id) {
1383 self.db
1384 .prepare("UPDATE margin_alerts SET resolved_at = ? WHERE id = ?")
1385 .bind(&[stamp.as_str().into(), alert.id.as_str().into()])?
1386 .run()
1387 .await?;
1388 }
1389 }
1390 let to = env.var("COSTS_ALERT_EMAIL").map(|v| v.to_string()).unwrap_or_default();
1391 if !to_email.is_empty() && !to.trim().is_empty() {
1392 let subject = format!("[g1t costs] {} margin alert{}", to_email.len(), if to_email.len() == 1 { "" } else { "s" });
1393 match email_staff(env, to.trim(), &subject, &to_email).await {
1394 Ok(()) => {
1395 for marker in kept.iter().filter_map(|k| k.strip_prefix("email:")) {
1396 self.db
1397 .prepare("UPDATE margin_alerts SET emailed_at = ? WHERE id = ?")
1398 .bind(&[stamp.as_str().into(), marker.into()])?
1399 .run()
1400 .await?;
1401 }
1402 }
1403 Err(error) => worker::console_error!("could not email the margin alerts: {error}"),
1404 }
1405 }
1406 Ok(conditions.len() as u32)
1407 }
1408
1409 /// Workspaces costing g1t more than they pay over 30 days, not g1t's own.
Margin alerts measure what is sold, and say dollars when a percentage would mislead1410 /// Each day's cost shared out to comped workspaces.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1411 async fn workspace_anomalies(&self, until: &str, settings: &CostSettings) -> Result<Vec<(String, i64, i64)>> {
1412 #[derive(Deserialize)]
1413 struct Row {
1414 workspace: String,
1415 cost: Option<i64>,
1416 revenue: Option<i64>,
1417 }
1418 let rows = self
1419 .db
1420 .prepare(format!(
Margin alerts measure what is sold, and say dollars when a percentage would mislead1421 // Against what its usage was priced at, not the cash it
1422 // paid: a trial or a gift paying for usage is not a price
1423 // below cost.
The workspace cost alert compares only days that carry their value, not the days before it was kept1424 // Days from before value_micros was kept have none: only days
1425 // since the first one that does are compared.
Margin alerts measure what is sold, and say dollars when a percentage would mislead1426 "SELECT workspace, SUM(cost_micros) AS cost, SUM(value_micros) AS revenue FROM workspace_costs
The workspace cost alert compares only days that carry their value, not the days before it was kept1427 WHERE day >= ?1 AND day <= ?2 AND workspace NOT IN ({})
1428 AND day >= (SELECT MIN(day) FROM workspace_costs WHERE value_micros > 0)
1429 GROUP BY workspace",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1430 crate::sales::INTERNAL_SQL
1431 ))
1432 .bind(&[day_before(until, ANOMALY_DAYS - 1).into(), until.into()])?
1433 .all()
1434 .await?
1435 .results::<Row>()?;
1436 let rows: Vec<(String, i64, i64)> = rows.into_iter().map(|r| (r.workspace, r.cost.unwrap_or(0), r.revenue.unwrap_or(0))).collect();
1437 Ok(anomalies(&rows, settings.anomaly_factor, settings.anomaly_floor_micros))
1438 }
1439
1440 /// For Reach out: workspaces with an open cost-over-revenue alert,
1441 /// each with its detail and cost.
1442 pub(crate) async fn costing_more_than_they_pay(&self) -> Result<Vec<(String, String, i64)>> {
1443 let alerts = self
1444 .db
1445 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL AND kind = 'workspace' ORDER BY opened_at DESC LIMIT 50")
1446 .all()
1447 .await?
1448 .results::<AlertRow>()?;
1449 let mut out = Vec::new();
1450 for alert in alerts {
1451 #[derive(Deserialize)]
1452 struct Cost {
1453 cost: Option<i64>,
1454 }
1455 let cost = self
1456 .db
1457 .prepare("SELECT SUM(cost_micros) AS cost FROM workspace_costs WHERE workspace = ? AND day >= ?")
1458 .bind(&[alert.subject.as_str().into(), alert.since.as_str().into()])?
1459 .first::<Cost>(None)
1460 .await?
1461 .and_then(|c| c.cost)
1462 .unwrap_or(0);
1463 out.push((alert.subject, alert.detail, cost));
1464 }
1465 Ok(out)
1466 }
1467
1468 /// `admin_cost_alerts`: what sudo's banner says.
1469 pub(crate) async fn admin_cost_alerts(&self, _: AdminCostAlertsArgs) -> Result<Vec<MarginAlert>> {
1470 Ok(self
1471 .db
1472 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL ORDER BY opened_at DESC LIMIT 50")
1473 .all()
1474 .await?
1475 .results::<AlertRow>()?
1476 .into_iter()
1477 .map(MarginAlert::from)
1478 .collect())
1479 }
1480
1481 /// `admin_run_costs`: the daily run, now.
1482 pub(crate) async fn admin_run_costs(&self, env: &Env, a: AdminRunCostsArgs) -> Result<Outcome<CostsRun>> {
1483 let keeper = crate::keeper::Keeper::from_env(env);
1484 let run = self.costs_daily(env, &keeper).await?;
1485 if !a.by.is_empty() {
1486 self.audit(
1487 "costs",
1488 "costs_run",
1489 &format!("{} lines, {} days, {} proposals, {} alerts", run.lines, run.days, run.proposals, run.alerts),
1490 &a.by,
1491 )
1492 .await?;
1493 }
1494 Ok(Outcome::Ok(run))
1495 }
1496
1497 /// `admin_set_cost_mapping`.
1498 pub(crate) async fn admin_set_cost_mapping(&self, a: AdminSetCostMappingArgs) -> Result<Outcome<CostMapping>> {
1499 let product = costs::slug(&a.product);
1500 let meter = if a.meter.trim() == "*" { "*".to_owned() } else { costs::slug(&a.meter) };
1501 if product.is_empty() || meter.is_empty() {
1502 return Ok(Outcome::fail(FailureCode::Invalid, "Name Cloudflare's product and a meter (or * for all of it)."));
1503 }
1504 let now = rfc3339(now_ms());
1505 if a.remove {
1506 self.db
1507 .prepare("DELETE FROM cost_map WHERE product = ? AND meter = ?")
1508 .bind(&[product.as_str().into(), meter.as_str().into()])?
1509 .run()
1510 .await?;
1511 self.audit("costs", "cost_mapping_removed", &format!("{product}/{meter}"), &a.by).await?;
1512 return Ok(Outcome::Ok(CostMapping {
1513 product,
1514 meter,
1515 bucket: String::new(),
1516 price_meter: None,
1517 own_meter: None,
1518 scale_to_own: false,
1519 drift_percent: 0.0,
1520 note: String::new(),
1521 updated_at: now,
1522 updated_by: a.by,
1523 }));
1524 }
1525 let bucket = costs::slug(&a.bucket);
1526 if bucket.is_empty() {
1527 return Ok(Outcome::fail(FailureCode::Invalid, "Say which of g1t's products it is a cost of."));
1528 }
1529 let clean = |v: Option<String>| v.map(|v| v.trim().to_owned()).filter(|v| !v.is_empty());
1530 let (price_meter, own_meter) = (clean(a.price_meter), clean(a.own_meter));
1531 let drift = a.drift_percent.filter(|d| d.is_finite() && *d > 0.0).unwrap_or(10.0);
1532 self.db
1533 .prepare(
1534 "INSERT INTO cost_map (product, meter, bucket, price_meter, own_meter, scale_to_own, drift_percent, note, updated_at, updated_by)
1535 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)
1536 ON CONFLICT (product, meter) DO UPDATE SET bucket = ?3, price_meter = ?4, own_meter = ?5, scale_to_own = ?6,
1537 drift_percent = ?7, note = ?8, updated_at = ?9, updated_by = ?10",
1538 )
1539 .bind(&[
1540 product.as_str().into(),
1541 meter.as_str().into(),
1542 bucket.as_str().into(),
1543 crate::optional(price_meter.as_deref()),
1544 crate::optional(own_meter.as_deref()),
1545 i32::from(a.scale_to_own).into(),
1546 drift.into(),
1547 a.note.trim().into(),
1548 now.as_str().into(),
1549 a.by.as_str().into(),
1550 ])?
1551 .run()
1552 .await?;
1553 self.audit("costs", "cost_mapping", &format!("{product}/{meter} → {bucket}"), &a.by).await?;
1554 Ok(Outcome::Ok(CostMapping {
1555 product,
1556 meter,
1557 bucket,
1558 price_meter,
1559 own_meter,
1560 scale_to_own: a.scale_to_own,
1561 drift_percent: drift,
1562 note: a.note.trim().to_owned(),
1563 updated_at: now,
1564 updated_by: a.by,
1565 }))
1566 }
1567
1568 /// `admin_costs`: the Costs & margin page.
1569 pub(crate) async fn admin_costs(&self, a: AdminCostsArgs, configured: bool) -> Result<CostsReport> {
1570 let until = rfc3339(now_ms())[..10].to_owned();
1571 let span = u64::from(a.days.unwrap_or(30).clamp(7, 90));
1572 let since = day_before(&until, span - 1);
1573 let days = self.margin_days(&since, &until).await?;
1574 let rules = self.rules().await?;
1575
1576 let mut products: BTreeMap<String, ProductMargin> = BTreeMap::new();
1577 let mut overall = OverallMargin::default();
1578 for d in &days {
1579 let p = products.entry(d.bucket.clone()).or_insert_with(|| ProductMargin {
1580 bucket: d.bucket.clone(),
1581 title: costs::bucket_title(&d.bucket),
1582 cost_source: if NOT_CLOUDFLARE.contains(&d.bucket.as_str()) { "ledger" } else { "cloudflare" }.into(),
1583 overhead: OVERHEAD.contains(&d.bucket.as_str()),
1584 ..ProductMargin::default()
1585 });
1586 p.cf_cost_micros += d.cf_cost_micros;
1587 p.own_cost_micros += d.own_cost_micros;
1588 p.value_micros += d.value_micros;
1589 p.cost_micros += d.cost();
1590 overall.cost_micros += d.cost();
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1591 overall.given_micros += d.given.total();
1592 if NOT_CLOUDFLARE.contains(&d.bucket.as_str()) {
1593 overall.models_cost_micros += d.cost();
1594 } else {
1595 overall.cloudflare_cost_micros += d.cost();
1596 }
1597 overall.given_comped_micros += d.given.comped;
1598 overall.given_free_micros += d.given.free;
1599 overall.given_trial_micros += d.given.trial;
1600 overall.given_pool_micros += d.given.pool;
Merge branch 'worktree-agent-a633ac0f7f66d419d'1601 overall.given_discount_micros += d.given.discount;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1602 let sold = (d.cost() - d.given.total()).max(0);
1603 if OVERHEAD.contains(&d.bucket.as_str()) {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1604 overall.plans_micros += d.cash_micros;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1605 overall.running_cost_micros += sold;
1606 } else if d.bucket == UNMAPPED {
1607 overall.usage_micros += d.cash_micros;
1608 overall.unmapped_cost_micros += sold;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1609 } else {
1610 overall.usage_micros += d.cash_micros;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1611 overall.usage_cost_micros += sold;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1612 }
1613 }
1614 for p in products.values_mut() {
1615 p.margin_micros = p.value_micros - p.cost_micros;
1616 p.margin_percent = margin_percent(p.value_micros, p.cost_micros);
1617 }
1618 let revenue = overall.usage_micros + overall.plans_micros;
1619 overall.margin_micros = revenue - overall.cost_micros;
1620 overall.margin_percent = margin_percent(revenue, overall.cost_micros);
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1621 let sold = (overall.cost_micros - overall.given_micros).max(0);
1622 overall.sold_margin_micros = revenue - sold;
1623 overall.sold_margin_percent = margin_percent(revenue, sold);
Costs: the plan's included usage counts as paid for the usage it covered, out of what plans leave for running g1t; the run button shows it is running with CSS alone (sudo ships no JavaScript)1624 // The plan's included usage was paid for by the plan's price: it is
1625 // money in for the usage it covered, and out of what the plans
1626 // leave for running g1t.
1627 #[derive(Deserialize)]
1628 struct Included {
1629 micros: Option<i64>,
1630 }
1631 overall.included_micros = self
1632 .db
1633 .prepare(format!(
1634 "SELECT SUM(COALESCE(credit_micros, 0)) AS micros FROM ledger
1635 WHERE kind = 'usage' AND created_at >= ?1 AND created_at <= ?2 AND workspace NOT IN ({})",
1636 crate::sales::INTERNAL_SQL
1637 ))
1638 .bind(&[since.as_str().into(), format!("{until}T23:59:59.999Z").into()])?
1639 .first::<Included>(None)
1640 .await?
1641 .and_then(|r| r.micros)
1642 .unwrap_or(0);
1643 let usage_in = overall.usage_micros + overall.included_micros;
1644 overall.usage_margin_micros = usage_in - overall.usage_cost_micros;
1645 overall.usage_margin_percent = margin_percent(usage_in, overall.usage_cost_micros);
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1646 let mut products: Vec<ProductMargin> = products.into_values().collect();
1647 products.sort_by_key(|p| std::cmp::Reverse(p.cost_micros.max(p.value_micros)));
1648
1649 #[derive(Deserialize)]
1650 struct DriftRow {
1651 bucket: String,
1652 kind: String,
1653 ours: f64,
1654 cloudflare: f64,
1655 delta_percent: Option<f64>,
1656 detail: String,
1657 found_at: String,
1658 }
1659 let drift = self
1660 .db
1661 .prepare("SELECT * FROM cost_drift ORDER BY kind, bucket")
1662 .all()
1663 .await?
1664 .results::<DriftRow>()?
1665 .into_iter()
1666 .map(|r| CostDrift {
1667 title: costs::bucket_title(&r.bucket),
1668 bucket: r.bucket,
1669 kind: r.kind,
1670 ours: r.ours,
1671 cloudflare: r.cloudflare,
1672 delta_percent: r.delta_percent,
1673 detail: r.detail,
1674 found_at: r.found_at,
1675 })
1676 .collect();
1677
1678 #[derive(Deserialize)]
1679 struct Top {
1680 workspace: String,
1681 cost: Option<i64>,
1682 revenue: Option<i64>,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1683 given: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1684 internal: i64,
1685 }
1686 let top_workspaces = self
1687 .db
1688 .prepare(format!(
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1689 "SELECT workspace, SUM(cost_micros) AS cost, SUM(revenue_micros) AS revenue, SUM(given_micros) AS given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1690 CASE WHEN workspace IN ({}) THEN 1 ELSE 0 END AS internal
1691 FROM workspace_costs WHERE day >= ?1 AND day <= ?2 GROUP BY workspace ORDER BY cost DESC LIMIT 15",
1692 crate::sales::INTERNAL_SQL
1693 ))
1694 .bind(&[since.as_str().into(), until.as_str().into()])?
1695 .all()
1696 .await?
1697 .results::<Top>()?
1698 .into_iter()
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1699 .map(|t| WorkspaceCost { workspace: t.workspace, cost_micros: t.cost.unwrap_or(0), revenue_micros: t.revenue.unwrap_or(0), given_micros: t.given.unwrap_or(0), internal: t.internal == 1 })
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1700 .collect();
1701
1702 #[derive(Deserialize)]
1703 struct Summary {
1704 source: String,
1705 product: String,
1706 meter: String,
1707 raw_name: String,
1708 unit: String,
1709 quantity: f64,
1710 cost_usd: f64,
1711 }
1712 let lines = self
1713 .db
1714 .prepare(
1715 "SELECT source, product, meter, MAX(raw_name) AS raw_name, MAX(unit) AS unit, SUM(quantity) AS quantity, SUM(cost_usd) AS cost_usd
1716 FROM cost_lines WHERE day >= ?1 AND day <= ?2 GROUP BY source, product, meter ORDER BY cost_usd DESC, product, meter LIMIT 200",
1717 )
1718 .bind(&[since.as_str().into(), until.as_str().into()])?
1719 .all()
1720 .await?
1721 .results::<Summary>()?
1722 .into_iter()
1723 .map(|l| CostLineSummary {
1724 bucket: costs::classify(&rules, &l.product, &l.meter).map(|r| r.bucket.clone()),
1725 product: l.product,
1726 meter: l.meter,
1727 raw_name: l.raw_name,
1728 unit: l.unit,
1729 source: l.source,
1730 quantity: l.quantity,
1731 cost_micros: micros(l.cost_usd),
1732 })
1733 .collect();
1734
1735 #[derive(Deserialize)]
1736 struct MapRow {
1737 product: String,
1738 meter: String,
1739 bucket: String,
1740 price_meter: Option<String>,
1741 own_meter: Option<String>,
1742 scale_to_own: i64,
1743 drift_percent: f64,
1744 note: String,
1745 updated_at: String,
1746 updated_by: String,
1747 }
1748 let mappings = self
1749 .db
1750 .prepare("SELECT * FROM cost_map ORDER BY product, meter")
1751 .all()
1752 .await?
1753 .results::<MapRow>()?
1754 .into_iter()
1755 .map(|m| CostMapping {
1756 product: m.product,
1757 meter: m.meter,
1758 bucket: m.bucket,
1759 price_meter: m.price_meter,
1760 own_meter: m.own_meter,
1761 scale_to_own: m.scale_to_own == 1,
1762 drift_percent: m.drift_percent,
1763 note: m.note,
1764 updated_at: m.updated_at,
1765 updated_by: m.updated_by,
1766 })
1767 .collect();
1768
1769 #[derive(Deserialize)]
1770 struct Fetched {
1771 at: Option<String>,
1772 }
1773 let fetched_at = self.db.prepare("SELECT MAX(fetched_at) AS at FROM cost_lines").first::<Fetched>(None).await?.and_then(|f| f.at);
1774
1775 Ok(CostsReport {
1776 configured,
1777 fetched_at,
1778 days: days
1779 .iter()
1780 .map(|d| CostDay {
1781 day: d.day.clone(),
1782 bucket: d.bucket.clone(),
1783 cf_cost_micros: d.cf_cost_micros,
1784 own_cost_micros: d.own_cost_micros,
1785 value_micros: d.value_micros,
1786 cash_micros: d.cash_micros,
1787 })
1788 .collect(),
1789 since,
1790 until,
1791 products,
1792 overall,
1793 drift,
1794 alerts: self.admin_cost_alerts(AdminCostAlertsArgs {}).await?,
1795 proposals: self.proposals().await?,
1796 versions: self.versions().await?,
1797 top_workspaces,
1798 lines,
1799 mappings,
1800 settings: self.cost_settings().await?,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1801 caps: self.spend_caps().await?,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1802 })
1803 }
1804}
1805
1806#[cfg(test)]
1807mod tests {
1808 use super::*;
1809
Margin alerts measure what is sold, and say dollars when a percentage would mislead1810 #[test]
Models' margin read -14%: usage nothing paid for is valued at price, not $01811 fn usage_nothing_paid_for_is_valued_at_price_and_paid_usage_at_what_was_paid() {
1812 // A free period: charged nothing, drawn from nothing.
1813 assert_eq!(usage_value(false, 1_000_000, 0, 20), 1_200_000);
1814 // Charged, or drawn from a trial: what was paid.
1815 assert_eq!(usage_value(false, 1_000_000, 1_200_000, 20), 1_200_000);
1816 assert_eq!(usage_value(false, 1_000_000, 900_000, 20), 900_000);
1817 // g1t's own: at price.
1818 assert_eq!(usage_value(true, 1_000_000, 0, 20), 1_200_000);
1819 // No cost, nothing paid: nothing.
1820 assert_eq!(usage_value(false, 0, 0, 20), 0);
1821 }
1822
1823 #[test]
Margin alerts measure what is sold, and say dollars when a percentage would mislead1824 fn the_overall_alert_says_dollars_while_little_comes_in() {
1825 let small = overall_detail(90_000, 7_500_000, 3, 10.0, -8239.7);
1826 assert!(small.contains("took in $0.09 against $7.50"), "{small}");
1827 assert!(!small.contains('%'), "{small}");
1828 let real = overall_detail(30_000_000, 40_000_000, 3, 10.0, -33.3);
1829 assert!(real.contains("as low as -33.3%"), "{real}");
1830 }
1831
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1832 fn rule(product: &str, meter: &str, bucket: &str, own: Option<&str>) -> Rule {
1833 Rule { product: product.into(), meter: meter.into(), bucket: bucket.into(), price_meter: None, own_meter: own.map(Into::into), drift_percent: 10.0 }
1834 }
1835
1836 fn rules() -> Vec<Rule> {
1837 vec![
1838 rule("containers", "*", "sandboxes", None),
1839 rule("workers", "*", "platform", None),
1840 rule("artifacts", "*", "git", Some("git_operations")),
1841 rule("artifacts", "events_", "git", Some("git_operations")),
1842 ]
1843 }
1844
1845 fn revenue_map() -> BTreeMap<String, String> {
1846 [("sandbox", "sandboxes"), ("git", "git"), ("plan", "platform")].iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()
1847 }
1848
1849 fn line(day: &str, source: &str, product: &str, meter: &str, quantity: f64, cost: f64) -> LineRow {
1850 LineRow { day: day.into(), source: source.into(), product: product.into(), meter: meter.into(), quantity, cost_usd: cost }
1851 }
1852
1853 fn usage(day: &str, workspace: &str, key: &str, value: i64, cash: i64, cost: i64) -> UsageRow {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1854 UsageRow { day: day.into(), workspace: workspace.into(), key: key.into(), value, cash, cost, given: Given::default() }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1855 }
1856
1857 #[test]
1858 fn a_day_puts_the_bill_g1ts_counts_and_charges_side_by_side() {
1859 let lines = vec![
1860 line("2026-10-15", SOURCE_BILLABLE, "containers", "container_memory", 1000.0, 2.00),
1861 line("2026-10-15", SOURCE_BILLABLE, "artifacts", "artifacts_operations", 30_000.0, 3.00),
1862 // Artifacts' own events: not used while the bill has a count.
1863 line("2026-10-15", SOURCE_ARTIFACTS, "artifacts", "events_pull", 29_000.0, 0.0),
1864 line("2026-10-15", SOURCE_BILLABLE, "workers", "workers_cpu_ms", 1.0, 0.50),
1865 line("2026-10-15", SOURCE_BILLABLE, "browser_rendering", "browser_hours", 2.0, 0.25),
1866 ];
1867 let own = vec![
1868 OwnRow { day: "2026-10-15".into(), meter: "git_operations".into(), workspace: "acme".into(), quantity: 7_500.0 },
1869 OwnRow { day: "2026-10-15".into(), meter: "git_operations".into(), workspace: "beta".into(), quantity: 2_500.0 },
1870 ];
1871 let usage = vec![
1872 usage("2026-10-15", "acme", "sandbox", 2_400_000, 1_000_000, 2_000_000),
1873 usage("2026-10-15", "beta", "sandbox", 1_200_000, 1_200_000, 1_000_000),
1874 usage("2026-10-15", "acme", "git", 600_000, 600_000, 500_000),
1875 usage("2026-10-15", "acme", "implement", 120_000, 120_000, 100_000),
1876 usage("2026-10-15", "beta", "plan", 20_000_000, 20_000_000, 0),
1877 ];
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1878 let (days, workspaces) = fold(&rules(), &revenue_map(), &lines, &own, &usage, &BTreeSet::new());
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1879 let get = |bucket: &str| days.iter().find(|d| d.bucket == bucket).unwrap();
1880 let sandboxes = get("sandboxes");
1881 assert_eq!((sandboxes.cf_cost_micros, sandboxes.own_cost_micros, sandboxes.value_micros, sandboxes.cash_micros), (2_000_000, 3_000_000, 3_600_000, 2_200_000));
1882 let git = get("git");
1883 assert_eq!(git.cf_cost_micros, 3_000_000);
1884 assert_eq!((git.cf_quantity, git.own_quantity), (30_000.0, 10_000.0));
1885 assert_eq!(get("platform").value_micros, 20_000_000);
1886 // Not mapped: a leak until someone maps it.
1887 assert_eq!(get(UNMAPPED).cf_cost_micros, 250_000);
1888 // Models: no Cloudflare line, their cost is g1t's own.
1889 assert_eq!(get("models").cost(), 100_000);
1890 // Git's cost shared by g1t's own counts (Cloudflare gave none per
1891 // workspace here): three quarters to acme.
1892 let share = |ws: &str, bucket: &str| workspaces.iter().find(|w| w.workspace == ws && w.bucket == bucket).map(|w| (w.cost, w.revenue));
1893 assert_eq!(share("acme", "git"), Some((2_250_000, 600_000)));
1894 assert_eq!(share("beta", "git"), Some((750_000, 0)));
1895 // Every bucket's cost is shared out exactly.
1896 for d in &days {
1897 let shared: i64 = workspaces.iter().filter(|w| w.bucket == d.bucket).map(|w| w.cost).sum();
1898 assert_eq!(shared, d.cost(), "{}", d.bucket);
1899 }
1900 }
1901
1902 #[test]
1903 fn artifacts_events_count_when_the_bill_does_not() {
1904 let lines = vec![
1905 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_pull", 120.0, 0.0),
1906 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_push", 30.0, 0.0),
1907 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_ratelimited", 9.0, 0.0),
1908 ];
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1909 let (days, _) = fold(&rules(), &revenue_map(), &lines, &[], &[], &BTreeSet::new());
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1910 assert_eq!(days[0].cf_quantity, 150.0);
1911 assert_eq!(days[0].cf_cost_micros, 0);
1912 }
1913
1914 #[test]
1915 fn month_end_meters_are_told_by_the_day_from_snapshots() {
1916 let snap = |day: &str, cost: i64, charge: i64| (day.to_string(), "acme".to_string(), "git".to_string(), cost, charge);
1917 let rows = pending_deltas(&[snap("2026-10-30", 100, 120), snap("2026-10-31", 250, 300), snap("2026-11-01", 40, 48), snap("2026-11-02", 40, 48)]);
1918 assert_eq!(
1919 rows.iter().map(|r| (r.day.as_str(), r.cost, r.value)).collect::<Vec<_>>(),
1920 vec![("2026-10-30", 100, 120), ("2026-10-31", 150, 180), ("2026-11-01", 40, 48)]
1921 );
1922 }
1923
1924 #[test]
1925 fn a_plan_payment_is_spread_over_the_month_it_pays_for() {
1926 let days = spread("2026-10-01T00:00:00.000Z", 20_000_000, 30);
1927 assert_eq!(days.len(), 30);
1928 assert_eq!(days[0], ("2026-10-01".to_string(), 666_667));
1929 assert_eq!(days[29], ("2026-10-30".to_string(), 666_666));
1930 assert_eq!(days.iter().map(|d| d.1).sum::<i64>(), 20_000_000);
1931 assert!(spread("2026-10-01", 0, 30).is_empty());
1932 assert_eq!(dollars(17_024_000), "$17.02");
1933 assert_eq!(dollars(-27_668_620), "-$27.67");
1934 assert_eq!(dollars(63_000), "$0.063");
1935 }
1936
1937 #[test]
1938 fn margins_and_deltas() {
1939 assert_eq!(margin_percent(1_200_000, 1_000_000).map(|m| (m * 100.0).round() / 100.0), Some(16.67));
1940 assert_eq!(margin_percent(0, 5), None);
1941 assert_eq!(delta_percent(110.0, 100.0), Some(10.0));
1942 assert_eq!(delta_percent(1.0, 0.0), None);
1943 }
1944
1945 fn day(bucket: &str, cf: i64, own: i64, value: i64, cfq: f64, ownq: f64) -> ProductDay {
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1946 ProductDay { day: "2026-10-15".into(), bucket: bucket.into(), cf_cost_micros: cf, own_cost_micros: own, value_micros: value, cash_micros: value, cf_quantity: cfq, own_quantity: ownq, given: Given::default() }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1947 }
1948
1949 #[test]
1950 fn counts_more_than_the_threshold_apart_are_drift() {
1951 // Cloudflare counted 30,000 operations where g1t counted 10,000:
1952 // binding reads, perhaps. -66.7%.
1953 let drift = drifts("git", &[day("git", 3_000_000, 1_500_000, 1_800_000, 30_000.0, 10_000.0)], 10.0, true, 100_000);
1954 assert_eq!(drift.iter().map(|d| d.kind).collect::<Vec<_>>(), vec![DriftKind::Count, DriftKind::Cost]);
1955 assert!((drift[0].delta_percent.unwrap() + 66.666).abs() < 0.01);
1956 // 9% apart: within 10%.
1957 assert!(drifts("git", &[day("git", 1_000_000, 1_000_000, 1_200_000, 10_000.0, 10_900.0)], 10.0, true, 100_000).is_empty());
1958 // Uncounted products have no count drift.
1959 assert!(drifts("sandboxes", &[day("sandboxes", 1_000_000, 1_050_000, 1_200_000, 5.0, 0.0)], 10.0, false, 100_000).is_empty());
1960 }
1961
1962 #[test]
1963 fn cost_with_no_revenue_is_a_leak_but_not_for_running_g1t() {
1964 let leak = drifts("actions_cache", &[day("actions_cache", 400_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000);
1965 assert_eq!(leak.len(), 1);
1966 assert_eq!(leak[0].kind, DriftKind::Leak);
1967 assert!(drifts("platform", &[day("platform", 5_000_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
1968 // Pennies say nothing.
1969 assert!(drifts("actions_cache", &[day("actions_cache", 50_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
1970 assert!(drifts(UNMAPPED, &[day(UNMAPPED, 250_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000)[0].kind == DriftKind::Leak);
1971 }
1972
1973 #[test]
1974 fn a_margin_alert_needs_n_days_in_a_row_under_the_floor() {
1975 let s = |d: &str, revenue: i64, cost: i64| (d.to_string(), revenue, cost);
1976 // 5%, 0%, -20%: three days under 10%.
1977 let series = vec![s("10-13", 1_200_000, 1_000_000), s("10-14", 1_050_000, 1_000_000), s("10-15", 1_000_000, 1_000_000), s("10-16", 1_000_000, 1_200_000)];
1978 let (from, worst) = breach(&series, 10.0, 3, 100_000).unwrap();
1979 assert_eq!(from, "10-14");
1980 assert!((worst + 20.0).abs() < 1e-9);
1981 // A good day in the window clears it.
1982 let mended = vec![s("10-14", 1_050_000, 1_000_000), s("10-15", 1_300_000, 1_000_000), s("10-16", 1_000_000, 1_200_000)];
1983 assert!(breach(&mended, 10.0, 3, 100_000).is_none());
1984 // Cost with no revenue at all is the worst margin there is.
1985 assert_eq!(breach(&[s("10-16", 0, 500_000)], 10.0, 1, 100_000).unwrap().1, -100.0);
1986 // Too little cost to judge.
1987 assert!(breach(&[s("10-16", 0, 5_000)], 10.0, 1, 100_000).is_none());
1988 assert!(breach(&series, 10.0, 9, 100_000).is_none());
1989 }
1990
1991 #[test]
1992 fn shared_costs_add_up_to_the_bill() {
1993 let w = |k: &str, v: f64| (k.to_string(), v);
1994 assert_eq!(attribute(100, &[w("a", 1.0), w("b", 1.0), w("c", 1.0)]), vec![("a".into(), 34), ("b".into(), 33), ("c".into(), 33)]);
1995 assert_eq!(attribute(10, &[w("a", 3.0), w("b", 1.0), w("a", 0.0)]), vec![("a".into(), 8), ("b".into(), 2)]);
1996 assert!(attribute(10, &[w("a", 0.0)]).is_empty());
1997 assert!(attribute(0, &[w("a", 1.0)]).is_empty());
1998 }
1999
2000 #[test]
Costs: counts are compared with Cloudflare's from the day g1t started counting, so days before a meter existed are not drift2001 fn counts_are_compared_from_the_day_g1t_started_counting() {
2002 let on = |day: &str, cf: f64, own: f64| ProductDay { day: day.into(), bucket: "git".into(), cf_quantity: cf, own_quantity: own, ..ProductDay::default() };
2003 // Five days of Cloudflare's count before g1t's meter, then two that match.
2004 let days = vec![on("2026-10-01", 500.0, 0.0), on("2026-10-05", 300.0, 0.0), on("2026-10-06", 210.0, 231.0), on("2026-10-07", 450.0, 458.0)];
2005 assert!(drifts("git", &days, 10.0, true, 0).iter().all(|d| d.kind != DriftKind::Count));
2006 // A real gap on the days both counted still shows.
2007 let days = vec![on("2026-10-01", 500.0, 0.0), on("2026-10-06", 400.0, 231.0), on("2026-10-07", 600.0, 300.0)];
2008 let found = drifts("git", &days, 10.0, true, 0);
2009 let count = found.iter().find(|d| d.kind == DriftKind::Count).unwrap();
2010 assert_eq!((count.ours, count.cloudflare), (531.0, 1000.0));
2011 // A meter that never counted is compared over every day.
2012 let days = vec![on("2026-10-06", 400.0, 0.0)];
2013 assert!(drifts("git", &days, 10.0, true, 0).iter().any(|d| d.kind == DriftKind::Count));
2014 }
2015
2016 #[test]
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2017 fn what_g1t_gives_away_is_kept_apart_from_what_it_sells() {
2018 let map = BTreeMap::new();
2019 // A comped workspace (all of it given), one in its trial (half paid
2020 // by the trial) and one paying in cash, all on models.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2021 let comped = usage("2026-10-15", "flagon", "agent", 1_200_000, 0, 1_000_000);
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2022 let mut trial = usage("2026-10-15", "acme", "agent", 1_200_000, 600_000, 1_000_000);
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2023 trial.given = Given { trial: 600_000, ..Given::default() };
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2024 let paying = usage("2026-10-15", "beta", "agent", 1_200_000, 1_200_000, 1_000_000);
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2025 // Nothing priced that day: free use.
2026 let free = usage("2026-10-15", "gamma", "agent", 0, 0, 1_000_000);
2027 let internal = BTreeSet::from(["flagon".to_string()]);
2028 let (days, workspaces) = fold(&[], &map, &[], &[], &[comped, trial, paying, free], &internal);
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2029 let models = days.iter().find(|d| d.bucket == "models").unwrap();
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2030 assert_eq!(models.cost(), 4_000_000);
Merge branch 'worktree-agent-a633ac0f7f66d419d'2031 assert_eq!(models.given, Given { comped: 1_000_000, free: 1_000_000, trial: 500_000, pool: 0, discount: 0 });
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running2032 let given = |w: &str| workspaces.iter().find(|x| x.workspace == w).unwrap().given.total();
2033 assert_eq!((given("flagon"), given("acme"), given("beta"), given("gamma")), (1_000_000, 500_000, 0, 1_000_000));
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it2034 }
2035
2036 #[test]
Merge branch 'worktree-agent-a633ac0f7f66d419d'2037 fn a_discounted_sale_keeps_its_margin_and_counts_the_discount_as_given() {
2038 // $1 of model cost at 20%, sold to an account with 30% off: charged
2039 // $0.84, and $0.36 below cost plus the margin given (as usage_rows
2040 // reads the ledger: value at price, the discount part given).
2041 let mut sale = usage("2026-10-15", "acme", "agent", 1_200_000, 840_000, 1_000_000);
2042 sale.given = Given { discount: 360_000, ..Given::default() };
2043 let (days, _) = fold(&[], &BTreeMap::new(), &[], &[], &[sale], &BTreeSet::new());
2044 let models = days.iter().find(|d| d.bucket == "models").unwrap();
2045 assert_eq!(models.value_micros, 1_200_000);
2046 assert_eq!(models.given, Given { discount: 300_000, ..Given::default() });
2047 // What was sold (cost less given) still makes the margin.
2048 let sold = models.cost() - models.given.total();
2049 assert_eq!(margin_percent(models.cash_micros, sold).map(|m| m.round()), Some(17.0));
2050 }
2051
2052 #[test]
2053 fn the_gateways_total_against_the_ledgers_model_cost_is_drift() {
2054 // The gateway priced $5 of g1t's own traffic; the ledger has $3.
2055 let short = drifts("models", &[day("models", 5_000_000, 3_000_000, 3_600_000, 0.0, 0.0)], 10.0, false, 100_000);
2056 assert_eq!(short.iter().map(|d| d.kind).collect::<Vec<_>>(), vec![DriftKind::Cost]);
2057 assert!((short[0].delta_percent.unwrap() + 40.0).abs() < 1e-9);
2058 // Gateway traffic with nothing on the ledger at all: cost drift and a leak.
2059 let none = drifts("models", &[day("models", 2_000_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000);
2060 assert_eq!(none.iter().map(|d| d.kind).collect::<Vec<_>>(), vec![DriftKind::Cost, DriftKind::Leak]);
Billing: AI Gateway's analytics are read with the token that can see them, and a gateway that priced nothing is said2061 // Within the threshold: nothing.
Merge branch 'worktree-agent-a633ac0f7f66d419d'2062 assert!(drifts("models", &[day("models", 1_050_000, 1_000_000, 1_200_000, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
Billing: AI Gateway's analytics are read with the token that can see them, and a gateway that priced nothing is said2063 // The gateway priced nothing against a ledger that has model cost:
2064 // not agreement (a token that cannot see AI Gateway reads as no
2065 // rows), so it is said. Under the minimum, or no model cost: nothing.
2066 let silent = drifts("models", &[day("models", 0, 1_000_000, 1_200_000, 0.0, 0.0)], 10.0, false, 100_000);
2067 assert_eq!(silent, vec![Drift { bucket: "models".into(), kind: DriftKind::Cost, ours: 1_000_000.0, cloudflare: 0.0, delta_percent: None }]);
2068 let said = models_detail(&silent[0], &costs::GatewayCaveats::default());
2069 assert!(said.contains("$1.00") && said.contains("priced nothing") && said.contains("AI Gateway: Read"), "{said}");
2070 assert!(drifts("models", &[day("models", 0, 50_000, 60_000, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
2071 assert!(drifts("models", &[day("models", 0, 0, 0, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
Merge branch 'worktree-agent-a633ac0f7f66d419d'2072 // The detail says which way and why it may be off.
2073 let caveats = costs::GatewayCaveats { cache_read_tokens: 3_000_000.0, unpriced: vec!["anthropic_claude_new_1".into()], ..Default::default() };
2074 let detail = models_detail(&short[0], &caveats);
2075 assert!(detail.contains("$5.00") && detail.contains("$3.00") && detail.contains("were not charged"), "{detail}");
2076 assert!(detail.contains("3,000,000 prompt-cache read") && detail.contains("no price for anthropic_claude_new_1"), "{detail}");
2077 }
2078
2079 #[test]
2080 fn model_usage_the_gateway_cannot_price_is_drift_even_when_the_totals_agree() {
2081 assert!(unpriced_drift(&costs::GatewayCaveats::default()).is_none());
2082 // Cache tokens alone are a note on the cost drift, not drift.
2083 assert!(unpriced_drift(&costs::GatewayCaveats { cache_write_tokens: 10.0, ..Default::default() }).is_none());
2084 let (drift, detail) = unpriced_drift(&costs::GatewayCaveats { unpriced: vec!["anthropic_claude_new_1".into()], short_runs: 2, ..Default::default() }).unwrap();
2085 assert_eq!((drift.bucket.as_str(), drift.kind.as_str()), ("models", "unpriced"));
2086 assert!(detail.contains("no price for anthropic_claude_new_1") && detail.contains("2 runs were settled"), "{detail}");
2087 }
2088
2089 #[test]
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily2090 fn a_workspace_that_costs_more_than_it_pays_is_flagged() {
2091 let rows = vec![("acme".to_string(), 5_000_000, 1_000_000), ("beta".to_string(), 900_000, 0), ("gamma".to_string(), 2_000_000, 3_000_000)];
2092 let found = anomalies(&rows, 1.0, 1_000_000);
2093 assert_eq!(found, vec![("acme".to_string(), 5_000_000, 1_000_000)]);
2094 // At twice its revenue as the threshold, $5 against $3 is fine.
2095 assert!(anomalies(&[("acme".to_string(), 5_000_000, 3_000_000)], 2.0, 1_000_000).is_empty());
2096 }
2097
2098 #[test]
2099 fn a_git_operation_costs_what_cloudflare_counts_for_it() {
2100 // $0.15 per 1,000 of Cloudflare's operations, on the charged days.
2101 let rate = billed_rate(&[(10_000.0, 0.0), (20_000.0, 3.0), (30_000.0, 4.5), (5_000.0, 0.75)]).unwrap();
2102 assert!((rate - 0.000_15).abs() < 1e-12);
2103 // Cloudflare counted 3 for every 1 g1t did: binding reads count.
2104 let per_op = derived_unit_cost(rate, 300_000.0, 100_000.0).unwrap();
2105 let per_thousand_micros = per_op * unit_size("1,000 operations") * 1e6;
2106 assert!((per_thousand_micros - 450_000.0).abs() < 1e-6, "{per_thousand_micros}");
2107 // Too few of g1t's units to say.
2108 assert!(derived_unit_cost(rate, 3_000.0, 500.0).is_none());
2109 assert!(billed_rate(&[(10_000.0, 0.0)]).is_none());
2110 assert_eq!(unit_size("million requests"), 1e6);
2111 assert_eq!(unit_size("second"), 1.0);
2112 }
2113}

This file's history is long; its oldest lines are credited to the oldest commit read.