g1t/services/billing/src/margin.rs

1,850 lines84,606 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
114/// open-source pool. The Team plan's included usage is paid for by the
115/// plan's price, so it is sold, not given.
116#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
117pub(crate) struct Given {
118 pub comped: i64,
119 pub free: i64,
120 pub trial: i64,
121 pub pool: i64,
122}
123
124impl Given {
125 pub fn total(&self) -> i64 {
126 self.comped + self.free + self.trial + self.pool
127 }
128
129 fn add(&mut self, other: &Given) {
130 self.comped += other.comped;
131 self.free += other.free;
132 self.trial += other.trial;
133 self.pool += other.pool;
134 }
135
136 /// The same shares of `cost` as these are of `value`, at most all of it.
137 fn of(&self, cost: i64, value: i64) -> Given {
138 let total = self.total();
139 if value <= 0 || cost <= 0 || total <= 0 {
140 return Given::default();
141 }
142 let given = cost as i128 * total.min(value) as i128 / value as i128;
143 let part = |x: i64| (given * x.max(0) as i128 / total as i128) as i64;
144 Given { comped: part(self.comped), free: part(self.free), trial: part(self.trial), pool: part(self.pool) }
145 }
146}
147
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily148/// What a workspace was charged for one key on one day.
149#[derive(Clone, Debug, Default, PartialEq)]
150pub(crate) struct UsageRow {
151 pub day: String,
152 pub workspace: String,
153 /// A ledger task (or `builds`), a month-end source, or `plan`.
154 pub key: String,
155 pub value: i64,
156 pub cash: i64,
157 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 it158 /// 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 running159 /// workspaces and in a free period, else what the trial and the pool
160 /// paid and the overruns g1t covered.
161 pub given: Given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily162}
163
164/// One workspace's share of a product's cost on one day.
165#[derive(Clone, Debug, PartialEq)]
166pub(crate) struct WorkspaceDay {
167 pub day: String,
168 pub workspace: String,
169 pub bucket: String,
170 pub cost: i64,
Margin alerts measure what is sold, and say dollars when a percentage would mislead171 /// What the workspace paid in cash.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily172 pub revenue: i64,
Margin alerts measure what is sold, and say dollars when a percentage would mislead173 /// What its usage was priced at, whoever paid for it.
174 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 running175 /// Of `cost`, the part g1t gave away: all of it for a comped workspace
176 /// or one with nothing priced that day (free use), else the cost times
177 /// the shares of its usage that day that g1t paid for.
178 pub given: Given,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily179}
180
181fn micros(dollars: f64) -> i64 {
182 (dollars * 1_000_000.0).round() as i64
183}
184
185/// Puts the day's bill, g1t's counts and what customers were charged side
186/// by side, a row per day and bucket, and shares each bucket's cost out
187/// to workspaces.
188pub(crate) fn fold(
189 rules: &[Rule],
190 revenue_map: &BTreeMap<String, String>,
191 lines: &[LineRow],
192 own: &[OwnRow],
193 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 running194 internal: &BTreeSet<String>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily195) -> (Vec<ProductDay>, Vec<WorkspaceDay>) {
196 let mut days: BTreeMap<(String, String), ProductDay> = BTreeMap::new();
197 let entry = |day: &str, bucket: &str| -> ProductDay {
198 ProductDay { day: day.to_owned(), bucket: bucket.to_owned(), ..ProductDay::default() }
199 };
200 // Which of g1t's own meters count each bucket's units.
201 let mut own_meters: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
202 for rule in rules {
203 if let Some(meter) = &rule.own_meter {
204 own_meters.entry(rule.bucket.as_str()).or_default().insert(meter.as_str());
205 }
206 }
207 let mut events: BTreeMap<(String, String), f64> = BTreeMap::new();
208 for line in lines {
209 let rule = costs::classify(rules, &line.product, &line.meter);
210 let bucket = rule.map_or(UNMAPPED, |r| r.bucket.as_str());
211 let key = (line.day.clone(), bucket.to_owned());
212 if line.source == SOURCE_ARTIFACTS {
213 // What Artifacts counted: operations only, and only where the
214 // bill does not count them itself.
215 if ARTIFACTS_OPERATIONS.contains(&line.meter.as_str()) {
216 *events.entry(key).or_default() += line.quantity;
217 }
218 continue;
219 }
220 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
221 row.cf_cost_micros += micros(line.cost_usd);
222 if line.source == SOURCE_BILLABLE && rule.is_some_and(|r| r.own_meter.is_some()) {
223 row.cf_quantity += line.quantity;
224 }
225 }
226 for (key, quantity) in events {
227 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
228 if row.cf_quantity == 0.0 {
229 row.cf_quantity = quantity;
230 }
231 }
232 // g1t's own counts of the same units, by bucket and by workspace.
233 let mut own_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
234 // Cloudflare's own count by workspace, where it gives one
235 // (`cloudflare_<bucket>`): the best way to share its cost.
236 let mut cf_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
237 for count in own {
238 if let Some(bucket) = count.meter.strip_prefix("cloudflare_") {
239 cf_by.entry((count.day.clone(), bucket.to_owned())).or_default().push((count.workspace.clone(), count.quantity));
240 continue;
241 }
242 for (bucket, meters) in &own_meters {
243 if meters.contains(count.meter.as_str()) {
244 let key = (count.day.clone(), (*bucket).to_owned());
245 days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1)).own_quantity += count.quantity;
246 own_by.entry(key).or_default().push((count.workspace.clone(), count.quantity));
247 }
248 }
249 }
250 // What customers were charged.
251 let bucket_of = |key: &str| revenue_map.get(key).cloned().unwrap_or_else(|| "models".to_owned());
252 let mut value_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
253 let mut cost_by: BTreeMap<(String, String), Vec<(String, f64)>> = BTreeMap::new();
254 let mut revenue: BTreeMap<(String, String, String), i64> = BTreeMap::new();
Margin alerts measure what is sold, and say dollars when a percentage would mislead255 let mut valued: BTreeMap<(String, String, String), i64> = BTreeMap::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily256 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 running257 let mut gave: BTreeMap<(String, String), (Given, i64)> = BTreeMap::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily258 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 it259 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 running260 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 it261 g.1 += u.value;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily262 let bucket = bucket_of(&u.key);
263 let key = (u.day.clone(), bucket.clone());
264 let row = days.entry(key.clone()).or_insert_with(|| entry(&key.0, &key.1));
265 row.own_cost_micros += u.cost;
266 row.value_micros += u.value;
267 row.cash_micros += u.cash;
268 value_by.entry(key.clone()).or_default().push((u.workspace.clone(), u.value as f64));
269 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 mislead270 *revenue.entry((u.day.clone(), u.workspace.clone(), bucket.clone())).or_default() += u.cash;
271 *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 daily272 active.entry(u.day.clone()).or_default().push((u.workspace.clone(), u.value.max(u.cost) as f64));
273 }
274 // 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 running275 // workspace, else by g1t's own count of its units, else by what its
276 // usage cost (so free use carries its own cost), else by what it was
277 // charged; running g1t, and what no one mapped, by each workspace's
278 // share of all usage that day.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily279 let mut shares: BTreeMap<(String, String, String), i64> = BTreeMap::new();
280 for ((day, bucket), row) in &days {
281 let key = (day.clone(), bucket.clone());
282 let weigh = |m: &BTreeMap<(String, String), Vec<(String, f64)>>| m.get(&key).filter(|w| w.iter().any(|(_, v)| *v > 0.0)).cloned();
283 let weights = if OVERHEAD.contains(&bucket.as_str()) || bucket == UNMAPPED {
284 active.get(day).cloned()
285 } 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 running286 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 daily287 };
288 for (workspace, micros) in attribute(row.cost(), &weights.unwrap_or_default()) {
289 *shares.entry((day.clone(), workspace, bucket.clone())).or_default() += micros;
290 }
291 }
292 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 it293 let workspaces: Vec<WorkspaceDay> = keys
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily294 .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 it295 .map(|(day, workspace, bucket)| {
296 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 running297 // The day's shares given away apply to every bucket, so a
298 // comped workspace's part of running g1t is given too. A
299 // workspace with nothing priced that day used g1t for free.
300 let given = if internal.contains(&workspace) {
301 Given { comped: cost, ..Given::default() }
302 } else {
303 match gave.get(&(day.clone(), workspace.clone())) {
304 Some((given, value)) if *value > 0 => given.of(cost, *value),
305 _ => Given { free: cost.max(0), ..Given::default() },
306 }
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it307 };
308 WorkspaceDay {
309 cost,
310 revenue: revenue.get(&(day.clone(), workspace.clone(), bucket.clone())).copied().unwrap_or(0),
311 value: valued.get(&(day.clone(), workspace.clone(), bucket.clone())).copied().unwrap_or(0),
312 given,
313 day,
314 workspace,
315 bucket,
316 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily317 })
318 .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 it319 for w in &workspaces {
320 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 running321 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 it322 }
323 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily324 (days.into_values().collect(), workspaces)
325}
326
327/// A month-end source's day, from the snapshots of what it had come to:
328/// each day's figure less the day before's in the same month (the first
329/// day of a month, or the first snapshot, is its own).
330pub(crate) fn pending_deltas(snapshots: &[(String, String, String, i64, i64)]) -> Vec<UsageRow> {
331 // (day, workspace, source, cost, charge), any order.
332 let mut sorted = snapshots.to_vec();
333 sorted.sort_by(|a, b| (&a.1, &a.2, &a.0).cmp(&(&b.1, &b.2, &b.0)));
334 let mut out = Vec::new();
335 let mut previous: Option<&(String, String, String, i64, i64)> = None;
336 for snap in &sorted {
337 let (day, workspace, source, cost, charge) = snap;
338 let (before_cost, before_charge) = match previous {
339 Some(p) if p.1 == *workspace && p.2 == *source && p.0[..7] == day[..7] => (p.3, p.4),
340 _ => (0, 0),
341 };
342 let (cost, charge) = ((cost - before_cost).max(0), (charge - before_charge).max(0));
343 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 running344 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 daily345 }
346 previous = Some(snap);
347 }
348 out
349}
350
351/// Margin as a share of what was charged, in percent; None when nothing was.
352pub(crate) fn margin_percent(revenue_micros: i64, cost_micros: i64) -> Option<f64> {
353 (revenue_micros > 0).then(|| (revenue_micros - cost_micros) as f64 * 100.0 / revenue_micros as f64)
354}
355
356/// How far `ours` is from `theirs`, in percent of theirs; None when theirs
357/// is nothing.
358pub(crate) fn delta_percent(ours: f64, theirs: f64) -> Option<f64> {
359 (theirs > 0.0).then(|| (ours - theirs) * 100.0 / theirs)
360}
361
362#[derive(Clone, Copy, Debug, PartialEq, Eq)]
363pub(crate) enum DriftKind {
364 /// g1t counted a different number of units than Cloudflare did.
365 Count,
366 /// What Cloudflare charged differs from what the price book says the
367 /// same usage cost.
368 Cost,
369 /// Cloudflare charged for something nothing charges customers for.
370 Leak,
371}
372
373impl DriftKind {
374 pub fn as_str(self) -> &'static str {
375 match self {
376 DriftKind::Count => "count",
377 DriftKind::Cost => "cost",
378 DriftKind::Leak => "leak",
379 }
380 }
381}
382
383#[derive(Clone, Debug, PartialEq)]
384pub(crate) struct Drift {
385 pub bucket: String,
386 pub kind: DriftKind,
387 pub ours: f64,
388 pub cloudflare: f64,
389 pub delta_percent: Option<f64>,
390}
391
392/// Drift over a window for one bucket: counts more than `threshold`
393/// percent apart, a bill that far from the price book's cost of the same
394/// usage, and cost with nothing charged for it. Under `min_cost_micros`
395/// in all, cost says nothing.
396pub(crate) fn drifts(bucket: &str, days: &[ProductDay], threshold: f64, counted: bool, min_cost_micros: i64) -> Vec<Drift> {
397 let overhead = OVERHEAD.contains(&bucket);
398 let sum = |f: &dyn Fn(&ProductDay) -> f64| days.iter().map(f).sum::<f64>();
399 let cf_cost = sum(&|d| d.cf_cost_micros as f64);
400 let own_cost = sum(&|d| d.own_cost_micros as f64);
401 let value = sum(&|d| d.value_micros as f64);
402 let (cf_quantity, own_quantity) = (sum(&|d| d.cf_quantity), sum(&|d| d.own_quantity));
403 let mut out = Vec::new();
404 if counted && cf_quantity > 0.0 {
405 let delta = delta_percent(own_quantity, cf_quantity);
406 if delta.is_some_and(|d| d.abs() > threshold) {
407 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Count, ours: own_quantity, cloudflare: cf_quantity, delta_percent: delta });
408 }
409 }
410 let enough = cf_cost.max(own_cost) >= min_cost_micros as f64;
411 if enough && !overhead && cf_cost > 0.0 && own_cost > 0.0 && !NOT_CLOUDFLARE.contains(&bucket) {
412 let delta = delta_percent(own_cost, cf_cost);
413 if delta.is_some_and(|d| d.abs() > threshold) {
414 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Cost, ours: own_cost, cloudflare: cf_cost, delta_percent: delta });
415 }
416 }
417 if !overhead && cf_cost >= min_cost_micros as f64 && value <= 0.0 {
418 out.push(Drift { bucket: bucket.into(), kind: DriftKind::Leak, ours: value, cloudflare: cf_cost, delta_percent: None });
419 }
420 out
421}
422
423/// When the last `days` in a row (each with enough cost to say something)
424/// were all under the floor: the first of them and the worst margin.
425/// Each item is a day's (day, revenue, cost).
426pub(crate) fn breach(series: &[(String, i64, i64)], floor_percent: f64, days: usize, min_cost_micros: i64) -> Option<(String, f64)> {
427 if days == 0 || series.len() < days {
428 return None;
429 }
430 let tail = &series[series.len() - days..];
431 let mut worst = f64::INFINITY;
432 for (_, revenue, cost) in tail {
433 if *cost < min_cost_micros {
434 return None;
435 }
436 let margin = margin_percent(*revenue, *cost).unwrap_or(-100.0);
437 if margin >= floor_percent {
438 return None;
439 }
440 worst = worst.min(margin);
441 }
442 Some((tail[0].0.clone(), worst))
443}
444
445/// `total` shared out in proportion to `weights`, in whole millionths that
446/// add up to it exactly (largest remainder first). Nothing to share, or no
447/// weight, shares nothing.
448pub(crate) fn attribute(total: i64, weights: &[(String, f64)]) -> Vec<(String, i64)> {
449 let mut merged: BTreeMap<String, f64> = BTreeMap::new();
450 for (key, w) in weights {
451 *merged.entry(key.clone()).or_default() += w.max(0.0);
452 }
453 let sum: f64 = merged.values().sum();
454 if total <= 0 || sum <= 0.0 {
455 return Vec::new();
456 }
457 let mut shares: Vec<(String, i64, f64)> = merged
458 .into_iter()
459 .map(|(key, w)| {
460 let exact = total as f64 * w / sum;
461 (key, exact.floor() as i64, exact - exact.floor())
462 })
463 .collect();
464 let mut left = total - shares.iter().map(|s| s.1).sum::<i64>();
465 let mut order: Vec<usize> = (0..shares.len()).collect();
466 order.sort_by(|a, b| shares[*b].2.total_cmp(&shares[*a].2).then(shares[*a].0.cmp(&shares[*b].0)));
467 for index in order {
468 if left <= 0 {
469 break;
470 }
471 shares[index].1 += 1;
472 left -= 1;
473 }
474 shares.into_iter().filter(|s| s.1 > 0).map(|(key, micros, _)| (key, micros)).collect()
475}
476
477/// Workspaces that cost g1t more than `factor` times what they paid, with
478/// at least `floor_micros` of cost: each (workspace, cost, revenue), the
479/// biggest gap first.
Models' margin read -14%: usage nothing paid for is valued at price, not $0480/// What a day's usage was worth at price. g1t's own workspaces are valued
481/// at price. So is usage nothing paid for, neither charged nor drawn from
482/// the plan, a trial, a pool or a gift (a free period): it was given away at
483/// its price, not sold for nothing. Anything paid keeps what it was paid, so
484/// a discount still shows as one.
485pub(crate) fn usage_value(internal: bool, cost: i64, paid: i64, margin_percent: u32) -> i64 {
486 if internal || (paid == 0 && cost > 0) {
487 return crate::credits::with_margin(cost, margin_percent);
488 }
489 paid
490}
491
Margin alerts measure what is sold, and say dollars when a percentage would mislead492/// What the overall alert says: the money as money, and a percentage only
493/// while there is enough coming in for one to mean something (a few cents
494/// against dollars of cost reads as -8000%).
495pub(crate) fn overall_detail(took: i64, spent: i64, days: usize, floor: f64, worst: f64) -> String {
496 if took < 1_000_000 * days as i64 {
497 return format!(
498 "All of g1t, comped workspaces left out: took in {} against {} of Cloudflare's bill over {days} days.",
499 dollars(took),
500 dollars(spent)
501 );
502 }
503 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}%.")
504}
505
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily506pub(crate) fn anomalies(rows: &[(String, i64, i64)], factor: f64, floor_micros: i64) -> Vec<(String, i64, i64)> {
507 let mut out: Vec<(String, i64, i64)> = rows
508 .iter()
509 .filter(|(_, cost, revenue)| *cost >= floor_micros && *cost as f64 > *revenue as f64 * factor)
510 .cloned()
511 .collect();
512 out.sort_by(|a, b| (b.1 - b.2).cmp(&(a.1 - a.2)).then(a.0.cmp(&b.0)));
513 out
514}
515
516/// Cloudflare's marginal rate for one of its units: the median over the
517/// charged days of cost over quantity, in dollars. None while the included
518/// amounts still cover it. Each item is a day's (quantity, cost).
519pub(crate) fn billed_rate(days: &[(f64, f64)]) -> Option<f64> {
520 let mut rates: Vec<f64> = days.iter().filter(|(q, c)| *q > 0.0 && *c > 0.0).map(|(q, c)| c / q).collect();
521 if rates.is_empty() {
522 return None;
523 }
524 rates.sort_by(f64::total_cmp);
525 Some(rates[rates.len() / 2])
526}
527
528/// What one of g1t's units costs, from Cloudflare's rate per its own unit
529/// and how many of Cloudflare's units each of g1t's took: if Cloudflare
530/// counts three operations for every git operation g1t counts, a git
531/// operation costs three of Cloudflare's. None without enough of g1t's
532/// units to say.
533pub(crate) fn derived_unit_cost(rate_per_cf_unit: f64, cf_units: f64, own_units: f64) -> Option<f64> {
534 (own_units >= MIN_UNITS && cf_units > 0.0 && rate_per_cf_unit > 0.0).then(|| rate_per_cf_unit * cf_units / own_units)
535}
536
537/// How many units a price is per: `1,000 operations` → 1,000, `million
538/// requests` → 1,000,000, `second` → 1.
539pub(crate) fn unit_size(unit: &str) -> f64 {
540 let first = unit.split_whitespace().next().unwrap_or_default().replace(',', "");
541 match first.as_str() {
542 "million" => 1_000_000.0,
543 "thousand" => 1_000.0,
544 n => n.parse().unwrap_or(1.0),
545 }
546}
547
548fn day_before(day: &str, days: u64) -> String {
549 let ms = g1t_contracts::time::parse_rfc3339(&format!("{day}T00:00:00Z")).unwrap_or(0);
550 rfc3339(ms.saturating_sub(days * DAY_MS))[..10].to_owned()
551}
552
553/// Dollars to the cent from a dollar up, finer below: `$17.02`, `$0.063`.
554fn dollars(micros: i64) -> String {
555 if micros.abs() >= 1_000_000 {
556 let cents = (micros as f64 / 10_000.0).round() as i64;
557 format!("{}${}.{:02}", if cents < 0 { "-" } else { "" }, cents.abs() / 100, cents.abs() % 100)
558 } else {
559 crate::features::dollars(micros)
560 }
561}
562
563/// The days a plan payment is spread over.
564const PLAN_DAYS: u64 = 30;
565
566/// `micros` paid on `day` spread evenly over `days` days from it, in
567/// whole micros that add up to it (the first days take the remainder).
568pub(crate) fn spread(day: &str, micros: i64, days: u64) -> Vec<(String, i64)> {
569 if micros <= 0 || days == 0 {
570 return Vec::new();
571 }
572 let start = g1t_contracts::time::parse_rfc3339(&format!("{}T00:00:00Z", &day[..10.min(day.len())])).unwrap_or(0);
573 let each = micros / days as i64;
574 let rest = micros % days as i64;
575 (0..days)
576 .map(|n| (rfc3339(start + n * DAY_MS)[..10].to_owned(), each + i64::from((n as i64) < rest)))
577 .collect()
578}
579
580// ---------------------------------------------------------------------
581// The daily run, and what sudo reads.
582// ---------------------------------------------------------------------
583
584#[derive(Serialize)]
585struct Mail<'a> {
586 to: &'a str,
587 from: &'a str,
588 subject: &'a str,
589 text: String,
590 html: String,
591}
592
593fn escape(text: &str) -> String {
594 text.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;").replace('"', "&quot;")
595}
596
597/// Emails staff through Cloudflare Email Sending, the `EMAIL` binding.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays598pub(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 daily599 let link = "https://sudo.g1t.sh/costs";
600 let text = format!("{}\n\nCosts & margin: {link}\n\nSent by g1t-billing's margin guard (COSTS_ALERT_EMAIL).\n", lines.join("\n\n"));
601 let mut html = String::from("<div style=\"font-family:system-ui,sans-serif;max-width:560px;margin:0 auto;padding:24px 16px;color:#16150f\">");
602 for line in lines {
603 html.push_str(&format!("<p style=\"font-size:15px;line-height:1.6\">{}</p>", escape(line)));
604 }
605 html.push_str(&format!(
606 "<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>"
607 ));
608 let mail = Mail { to, from: "g1t <noreply@g1t.sh>", subject, text, html };
609 let binding = g1t_kit::js::binding(env, "EMAIL")?;
610 g1t_kit::js::call(&binding, "send", &[g1t_kit::js::to_js(&mail)?]).await?;
611 Ok(())
612}
613
614#[derive(Deserialize)]
615struct AlertRow {
616 id: String,
617 kind: String,
618 subject: String,
619 detail: String,
620 since: String,
621 opened_at: String,
622 emailed_at: Option<String>,
623}
624
625impl From<AlertRow> for MarginAlert {
626 fn from(r: AlertRow) -> Self {
627 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 }
628 }
629}
630
631#[derive(Deserialize)]
632struct MarginRow {
633 day: String,
634 bucket: String,
635 cf_cost_micros: i64,
636 own_cost_micros: i64,
637 value_micros: i64,
638 cash_micros: i64,
639 cf_quantity: f64,
640 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 it641 #[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 running642 given_comped_micros: Option<i64>,
643 #[serde(default)]
644 given_free_micros: Option<i64>,
645 #[serde(default)]
646 given_trial_micros: Option<i64>,
647 #[serde(default)]
648 given_pool_micros: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily649}
650
651impl From<MarginRow> for ProductDay {
652 fn from(r: MarginRow) -> Self {
653 ProductDay {
654 day: r.day,
655 bucket: r.bucket,
656 cf_cost_micros: r.cf_cost_micros,
657 own_cost_micros: r.own_cost_micros,
658 value_micros: r.value_micros,
659 cash_micros: r.cash_micros,
660 cf_quantity: r.cf_quantity,
661 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 running662 given: Given {
663 comped: r.given_comped_micros.unwrap_or(0),
664 free: r.given_free_micros.unwrap_or(0),
665 trial: r.given_trial_micros.unwrap_or(0),
666 pool: r.given_pool_micros.unwrap_or(0),
667 },
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily668 }
669 }
670}
671
672impl Billing {
673 /// The day's work: read Cloudflare's bill and g1t's own counts,
674 /// reconcile, look for drift, measure unit costs, apply prices whose
675 /// day has come, and raise or clear alerts.
676 pub(crate) async fn costs_daily(&self, env: &Env, keeper: &crate::keeper::Keeper) -> Result<CostsRun> {
677 let mut run = CostsRun::default();
678 let (since, until) = match self.read_cloudflare(keeper, &mut run.problems).await? {
679 Some((since, until, lines)) => {
680 run.lines = lines;
681 (since, until)
682 }
683 // Without the bill, still reconcile what g1t knows itself, over
684 // the same days the bill would be read for.
685 None => {
686 #[derive(Deserialize)]
687 struct Last {
688 day: Option<String>,
689 }
690 let last = self.db.prepare("SELECT MAX(day) AS day FROM margin_days").first::<Last>(None).await?.and_then(|l| l.day);
691 costs::window(last.as_deref(), now_ms())
692 }
693 };
694 if let Err(error) = self.count_own(&since, &until).await {
695 run.problems.push(format!("g1t's own counts could not be read: {error}"));
696 }
697 self.snapshot_pending(&until).await?;
Models' margin read -14%: usage nothing paid for is valued at price, not $0698 // Reconciled over the whole window sudo shows, not only the days the
699 // bill was read for: it reads only what is already kept, so a change
700 // in how a day is valued reaches every day shown at the next run.
701 let window = day_before(&until, costs::BACKFILL_DAYS - 1);
702 let reconcile_from = if window < since { window } else { since.clone() };
703 run.days = self.reconcile_range(&reconcile_from, &until).await?;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily704 let drift = self.find_drift(&until).await?;
705 run.proposals = self.measure_units(&until).await?;
706 self.apply_due_versions().await?;
707 run.alerts = self.raise_alerts(env, &until, &drift).await?;
708 if let Some(identity) = &self.identity
709 && let Err(error) = self.tell_owners_of_rises(identity).await
710 {
711 run.problems.push(format!("owners could not be told of a price rise: {error}"));
712 }
713 for problem in &run.problems {
714 worker::console_warn!("costs: {problem}");
715 }
716 Ok(run)
717 }
718
719 /// What each month-end source had come to by the end of `day`.
720 async fn snapshot_pending(&self, day: &str) -> Result<()> {
721 self.db
722 .prepare(
723 "INSERT INTO pending_days (day, workspace, source, cost_micros, charge_micros)
724 SELECT ?1, workspace, source, COALESCE(cost_micros, 0), COALESCE(charge_micros, 0) FROM pending_usage WHERE month = ?2
725 ON CONFLICT (day, workspace, source) DO UPDATE SET cost_micros = excluded.cost_micros, charge_micros = excluded.charge_micros",
726 )
727 .bind(&[day.into(), day[..7].into()])?
728 .run()
729 .await?;
730 Ok(())
731 }
732
733 /// What customers were charged on the days, by workspace and key.
734 async fn usage_rows(&self, since: &str, until: &str) -> Result<Vec<UsageRow>> {
735 #[derive(Deserialize)]
736 struct Row {
737 day: String,
738 workspace: String,
739 key: String,
740 internal: i64,
741 own_provider: i64,
742 cash: Option<i64>,
743 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 running744 trial: Option<i64>,
745 oss: Option<i64>,
746 covered: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily747 cost: Option<i64>,
748 }
749 let charged_here = crate::storage::CHARGED_HERE.iter().map(|s| format!("'{s}'")).collect::<Vec<_>>().join(", ");
750 let end = format!("{until}T23:59:59.999Z");
751 let rows = self
752 .db
753 .prepare(format!(
754 "SELECT substr(created_at, 1, 10) AS day, workspace,
755 CASE WHEN task = 'deployments' AND reference LIKE 'deploy/%' THEN 'builds' ELSE COALESCE(task, 'other') END AS key,
756 CASE WHEN workspace IN ({internal}) THEN 1 ELSE 0 END AS internal,
757 CASE WHEN billed_to = 'workspace' THEN 1 ELSE 0 END AS own_provider,
758 -SUM(amount_micros) AS cash,
759 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 running760 SUM(COALESCE(trial_micros, 0)) AS trial,
761 SUM(COALESCE(oss_micros, 0)) AS oss,
762 SUM(COALESCE(given_micros, 0)) AS covered,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily763 SUM(COALESCE(cost_micros, 0)) AS cost
764 FROM ledger
765 WHERE kind = 'usage' AND created_at >= ?1 AND created_at <= ?2 AND COALESCE(task, '') NOT IN ({charged_here})
766 GROUP BY 1, 2, 3, 4, 5",
767 internal = crate::sales::INTERNAL_SQL
768 ))
769 .bind(&[since.into(), end.as_str().into()])?
770 .all()
771 .await?
772 .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 it773 let mut internal = BTreeSet::new();
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily774 let mut out: Vec<UsageRow> = rows
775 .into_iter()
776 .map(|r| {
777 // A workspace's own model provider was paid there: no cost
778 // to g1t. g1t's own workspaces are valued at price.
779 let cost = if r.own_provider == 1 { 0 } else { r.cost.unwrap_or(0) };
780 let cash = r.cash.unwrap_or(0);
Models' margin read -14%: usage nothing paid for is valued at price, not $0781 let paid = cash + r.drawn.unwrap_or(0);
782 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 running783 let given = if r.internal == 1 {
784 Given { comped: value, ..Given::default() }
785 } else if paid == 0 && cost > 0 {
786 Given { free: value, ..Given::default() }
787 } else {
788 Given { free: r.covered.unwrap_or(0), trial: r.trial.unwrap_or(0), pool: r.oss.unwrap_or(0), comped: 0 }
789 };
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it790 if r.internal == 1 {
791 internal.insert(r.workspace.clone());
792 }
793 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 daily794 })
795 .collect();
796 // Month-end sources, from their daily snapshots.
797 #[derive(Deserialize)]
798 struct Snap {
799 day: String,
800 workspace: String,
801 source: String,
802 cost_micros: i64,
803 charge_micros: i64,
804 }
805 let snaps = self
806 .db
807 .prepare("SELECT day, workspace, source, cost_micros, charge_micros FROM pending_days WHERE day >= ?1 AND day <= ?2")
808 .bind(&[day_before(since, 1).into(), until.into()])?
809 .all()
810 .await?
811 .results::<Snap>()?
812 .into_iter()
813 .filter(|s| crate::storage::CHARGED_HERE.contains(&s.source.as_str()) || s.source == "domains")
814 .map(|s| (s.day, s.workspace, s.source, s.cost_micros, s.charge_micros))
815 .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 it816 out.extend(pending_deltas(&snaps).into_iter().filter(|u| u.day.as_str() >= since).map(|mut u| {
817 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 running818 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 it819 }
820 u
821 }));
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily822 // The plan's price, spread over the 30 days it pays for, so a month's
823 // payment does not read as one very good day and 29 bad ones.
824 #[derive(Deserialize)]
825 struct Plan {
826 day: String,
827 workspace: String,
828 micros: Option<i64>,
829 }
830 let plans = self
831 .db
832 .prepare(
833 "SELECT substr(paid_at, 1, 10) AS day, workspace, SUM(amount_micros) AS micros FROM plan_payments
834 WHERE paid_at >= ?1 AND paid_at <= ?2 GROUP BY 1, 2",
835 )
836 .bind(&[day_before(since, PLAN_DAYS - 1).into(), end.as_str().into()])?
837 .all()
838 .await?
839 .results::<Plan>()?;
840 for p in plans {
841 for (day, micros) in spread(&p.day, p.micros.unwrap_or(0), PLAN_DAYS) {
842 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 running843 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 daily844 }
845 }
846 }
847 Ok(out)
848 }
849
850 /// Reconciles the days and writes `margin_days` and `workspace_costs`.
851 async fn reconcile_range(&self, since: &str, until: &str) -> Result<u32> {
852 let rules = self.rules().await?;
853 #[derive(Deserialize)]
854 struct Map {
855 key: String,
856 bucket: String,
857 }
858 let revenue_map: BTreeMap<String, String> = self
859 .db
860 .prepare("SELECT key, bucket FROM revenue_map")
861 .all()
862 .await?
863 .results::<Map>()?
864 .into_iter()
865 .map(|m| (m.key, m.bucket))
866 .collect();
867 let lines = self
868 .db
869 .prepare("SELECT day, source, product, meter, quantity, cost_usd FROM cost_lines WHERE day >= ?1 AND day <= ?2")
870 .bind(&[since.into(), until.into()])?
871 .all()
872 .await?
873 .results::<LineRow>()?;
874 let own = self
875 .db
876 .prepare("SELECT day, meter, workspace, quantity FROM own_counts WHERE day >= ?1 AND day <= ?2")
877 .bind(&[since.into(), until.into()])?
878 .all()
879 .await?
880 .results::<OwnRow>()?;
881 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 running882 #[derive(Deserialize)]
883 struct Internal {
884 workspace: String,
885 }
886 let internal: BTreeSet<String> = self
887 .db
888 .prepare(format!("WITH i(workspace) AS ({}) SELECT DISTINCT workspace FROM i", crate::sales::INTERNAL_SQL))
889 .all()
890 .await?
891 .results::<Internal>()?
892 .into_iter()
893 .map(|i| i.workspace)
894 .collect();
895 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 daily896 let now = rfc3339(now_ms());
897 self.db
898 .batch(vec![
899 self.db.prepare("DELETE FROM margin_days WHERE day >= ?1 AND day <= ?2").bind(&[since.into(), until.into()])?,
900 self.db.prepare("DELETE FROM workspace_costs WHERE day >= ?1 AND day <= ?2").bind(&[since.into(), until.into()])?,
901 ])
902 .await?;
903 for chunk in days.chunks(50) {
904 let mut statements = Vec::with_capacity(chunk.len());
905 for d in chunk {
906 statements.push(
907 self.db
908 .prepare(
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 "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, computed_at)
910 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily911 )
912 .bind(&[
913 d.day.as_str().into(),
914 d.bucket.as_str().into(),
915 (d.cf_cost_micros as f64).into(),
916 (d.own_cost_micros as f64).into(),
917 (d.value_micros as f64).into(),
918 (d.cash_micros as f64).into(),
919 d.cf_quantity.into(),
920 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 running921 (d.given.total() as f64).into(),
922 (d.given.comped as f64).into(),
923 (d.given.free as f64).into(),
924 (d.given.trial as f64).into(),
925 (d.given.pool as f64).into(),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily926 now.as_str().into(),
927 ])?,
928 );
929 }
930 self.db.batch(statements).await?;
931 }
932 for chunk in workspaces.chunks(50) {
933 let mut statements = Vec::with_capacity(chunk.len());
934 for w in chunk {
935 statements.push(
936 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 it937 .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 daily938 .bind(&[
939 w.day.as_str().into(),
940 w.workspace.as_str().into(),
941 w.bucket.as_str().into(),
942 (w.cost as f64).into(),
943 (w.revenue as f64).into(),
Margin alerts measure what is sold, and say dollars when a percentage would mislead944 (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 running945 (w.given.total() as f64).into(),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily946 ])?,
947 );
948 }
949 self.db.batch(statements).await?;
950 }
951 Ok(costs::days_between(since, until).len() as u32)
952 }
953
954 async fn margin_days(&self, since: &str, until: &str) -> Result<Vec<ProductDay>> {
955 Ok(self
956 .db
957 .prepare("SELECT * FROM margin_days WHERE day >= ?1 AND day <= ?2 ORDER BY day, bucket")
958 .bind(&[since.into(), until.into()])?
959 .all()
960 .await?
961 .results::<MarginRow>()?
962 .into_iter()
963 .map(ProductDay::from)
964 .collect())
965 }
966
967 /// Drift over the last week, written to `cost_drift` (replacing the
968 /// last run's), with unmapped Cloudflare meters as leaks.
969 async fn find_drift(&self, until: &str) -> Result<Vec<(Drift, String)>> {
970 let since = day_before(until, DRIFT_DAYS - 1);
971 let settings = self.cost_settings().await?;
972 let rules = self.rules().await?;
973 let days = self.margin_days(&since, until).await?;
974 let mut by: BTreeMap<String, Vec<ProductDay>> = BTreeMap::new();
975 for d in days {
976 by.entry(d.bucket.clone()).or_default().push(d);
977 }
978 let mut found = Vec::new();
979 for (bucket, days) in &by {
980 let bucket_rules: Vec<&Rule> = rules.iter().filter(|r| &r.bucket == bucket).collect();
981 let threshold = bucket_rules.iter().map(|r| r.drift_percent).fold(f64::INFINITY, f64::min);
982 let threshold = if threshold.is_finite() { threshold } else { 10.0 };
983 let counted = bucket_rules.iter().any(|r| r.own_meter.is_some());
984 for drift in drifts(bucket, days, threshold, counted, settings.min_daily_cost_micros) {
985 let title = costs::bucket_title(bucket);
986 let detail = match drift.kind {
987 DriftKind::Count => format!(
One operation mapping, owned by repos; billing reads it instead of keeping its own988 "{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 daily989 crate::features::thousands(drift.ours.max(0.0).round() as u64),
990 crate::features::thousands(drift.cloudflare.max(0.0).round() as u64),
991 drift.delta_percent.unwrap_or(0.0)
992 ),
993 DriftKind::Cost => format!(
994 "{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.",
995 dollars(drift.cloudflare as i64),
996 dollars(drift.ours as i64),
997 drift.delta_percent.unwrap_or(0.0)
998 ),
999 DriftKind::Leak if bucket == UNMAPPED => {
1000 format!("Cloudflare charged {} for meters no mapping claims. Map them on Costs & margin.", dollars(drift.cloudflare as i64))
1001 }
1002 DriftKind::Leak => format!(
1003 "{title}: Cloudflare charged {} over the last {DRIFT_DAYS} days and customers were charged nothing for it.",
1004 dollars(drift.cloudflare as i64)
1005 ),
1006 };
1007 found.push((drift, detail));
1008 }
1009 }
1010 let now = rfc3339(now_ms());
1011 let mut statements = vec![self.db.prepare("DELETE FROM cost_drift")];
1012 for (drift, detail) in &found {
1013 statements.push(
1014 self.db
1015 .prepare("INSERT OR REPLACE INTO cost_drift (bucket, kind, ours, cloudflare, delta_percent, detail, found_at) VALUES (?, ?, ?, ?, ?, ?, ?)")
1016 .bind(&[
1017 drift.bucket.as_str().into(),
1018 drift.kind.as_str().into(),
1019 drift.ours.into(),
1020 drift.cloudflare.into(),
1021 drift.delta_percent.map_or(JsValue::NULL, JsValue::from),
1022 detail.as_str().into(),
1023 now.as_str().into(),
1024 ])?,
1025 );
1026 }
1027 self.db.batch(statements).await?;
1028 Ok(found)
1029 }
1030
1031 /// Unit costs from the bill for mappings that scale to g1t's own count
1032 /// (git operations), proposed to the price book.
1033 async fn measure_units(&self, until: &str) -> Result<u32> {
1034 #[derive(Deserialize)]
1035 struct Scaled {
1036 product: String,
1037 meter: String,
1038 price_meter: String,
1039 own_meter: String,
1040 unit: Option<String>,
1041 }
1042 let scaled = self
1043 .db
1044 .prepare(
1045 "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
1046 WHERE m.scale_to_own = 1 AND m.price_meter IS NOT NULL AND m.own_meter IS NOT NULL",
1047 )
1048 .all()
1049 .await?
1050 .results::<Scaled>()?;
1051 let since = day_before(until, MEASURE_DAYS - 1);
1052 let rules = self.rules().await?;
1053 let mut proposed = 0;
1054 for s in scaled {
1055 #[derive(Deserialize)]
1056 struct Day {
1057 product: String,
1058 meter: String,
1059 quantity: f64,
1060 cost_usd: f64,
1061 }
1062 let lines = self
1063 .db
1064 .prepare("SELECT product, meter, quantity, cost_usd FROM cost_lines WHERE source = ?1 AND product = ?2 AND day >= ?3 AND day <= ?4")
1065 .bind(&[SOURCE_BILLABLE.into(), s.product.as_str().into(), since.as_str().into(), until.into()])?
1066 .all()
1067 .await?
1068 .results::<Day>()?;
1069 // Only the lines this very mapping claims.
1070 let mine: Vec<(f64, f64)> = lines
1071 .iter()
1072 .filter(|l| costs::classify(&rules, &l.product, &l.meter).is_some_and(|r| r.product == s.product && r.meter == s.meter))
1073 .map(|l| (l.quantity, l.cost_usd))
1074 .collect();
1075 let Some(rate) = billed_rate(&mine) else { continue };
1076 let cf_units: f64 = mine.iter().map(|(q, _)| q).sum();
1077 #[derive(Deserialize)]
1078 struct Own {
1079 total: Option<f64>,
1080 }
1081 let own_units = self
1082 .db
1083 .prepare("SELECT SUM(quantity) AS total FROM own_counts WHERE meter = ?1 AND day >= ?2 AND day <= ?3")
1084 .bind(&[s.own_meter.as_str().into(), since.as_str().into(), until.into()])?
1085 .first::<Own>(None)
1086 .await?
1087 .and_then(|o| o.total)
1088 .unwrap_or(0.0);
1089 let Some(per_unit) = derived_unit_cost(rate, cf_units, own_units) else { continue };
1090 let size = unit_size(s.unit.as_deref().unwrap_or("1"));
1091 let measured = per_unit * size * 1_000_000.0;
1092 let reason = format!(
1093 "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 {})",
1094 rate * 1000.0,
1095 cf_units / own_units,
1096 crate::features::thousands(cf_units.round() as u64),
1097 crate::features::thousands(own_units.round() as u64)
1098 );
1099 if self.propose(&s.price_meter, measured, &reason, "reconciler").await?.is_some() {
1100 proposed += 1;
1101 }
1102 }
1103 Ok(proposed)
1104 }
1105
1106 /// Opens, updates and closes margin alerts, and emails staff about new
1107 /// ones (and open ones each week).
1108 async fn raise_alerts(&self, env: &Env, until: &str, drift: &[(Drift, String)]) -> Result<u32> {
1109 let settings = self.cost_settings().await?;
1110 let since = day_before(until, u64::from(settings.alert_days.max(1)) - 1);
1111 let days = self.margin_days(&since, until).await?;
1112 let mut conditions: Vec<(String, String, String, String)> = Vec::new();
1113 // Each product under the floor.
1114 let mut by: BTreeMap<String, Vec<(String, i64, i64)>> = BTreeMap::new();
1115 let mut all: BTreeMap<String, (i64, i64)> = BTreeMap::new();
1116 for d in &days {
1117 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 it1118 // What g1t gave away (comped workspaces, free periods, the
1119 // trial and the pools) is a budget it chose to spend, watched on
1120 // 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 daily1121 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 running1122 overall.1 += (d.cost() - d.given.total()).max(0);
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1123 if !OVERHEAD.contains(&d.bucket.as_str()) && d.bucket != UNMAPPED {
1124 by.entry(d.bucket.clone()).or_default().push((d.day.clone(), d.value_micros, d.cost()));
1125 }
1126 }
1127 let floor = settings.margin_floor_percent;
1128 let n = settings.alert_days as usize;
1129 for (bucket, series) in &by {
1130 if let Some((from, worst)) = breach(series, floor, n, settings.min_daily_cost_micros) {
1131 conditions.push((
1132 "margin".into(),
1133 bucket.clone(),
1134 format!("{}: margin under {floor:.0}% for {n} days running, as low as {worst:.1}%.", costs::bucket_title(bucket)),
1135 from,
1136 ));
Margin alerts measure what is sold, and say dollars when a percentage would mislead1137 }
1138 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1139 let series: Vec<(String, i64, i64)> = all.into_iter().map(|(day, (revenue, cost))| (day, revenue, cost)).collect();
1140 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 mislead1141 let tail = &series[series.len().saturating_sub(n)..];
1142 let (took, spent) = tail.iter().fold((0i64, 0i64), |(r, c), (_, revenue, cost)| (r + revenue, c + cost));
1143 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 daily1144 }
1145 for (d, detail) in drift {
1146 let kind = if d.kind == DriftKind::Leak { "leak" } else { "drift" };
1147 conditions.push((kind.into(), format!("{}:{}", d.bucket, d.kind.as_str()), detail.clone(), until.to_owned()));
1148 }
1149 // Workspaces costing more than they pay.
1150 for (workspace, cost, revenue) in self.workspace_anomalies(until, &settings).await? {
1151 conditions.push((
1152 "workspace".into(),
1153 workspace.clone(),
Margin alerts measure what is sold, and say dollars when a percentage would mislead1154 format!(
1155 "{workspace} cost g1t {} on Cloudflare over {ANOMALY_DAYS} days, and its usage was priced at {}: its prices are below cost.",
1156 dollars(cost),
1157 dollars(revenue)
1158 ),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1159 day_before(until, ANOMALY_DAYS - 1),
1160 ));
1161 }
1162
1163 let open = self
1164 .db
1165 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL")
1166 .all()
1167 .await?
1168 .results::<AlertRow>()?;
1169 let now = now_ms();
1170 let stamp = rfc3339(now);
1171 let mut to_email: Vec<String> = Vec::new();
1172 let mut kept: BTreeSet<String> = BTreeSet::new();
1173 for (kind, subject, detail, from) in &conditions {
1174 match open.iter().find(|a| &a.kind == kind && &a.subject == subject) {
1175 Some(alert) => {
1176 kept.insert(alert.id.clone());
1177 self.db
1178 .prepare("UPDATE margin_alerts SET detail = ? WHERE id = ?")
1179 .bind(&[detail.as_str().into(), alert.id.as_str().into()])?
1180 .run()
1181 .await?;
1182 let stale = alert
1183 .emailed_at
1184 .as_deref()
1185 .and_then(g1t_contracts::time::parse_rfc3339)
1186 .is_none_or(|at| now.saturating_sub(at) >= REMIND_MS);
1187 if stale && kind != "workspace" {
1188 to_email.push(format!("Still open: {detail}"));
1189 kept.insert(format!("email:{}", alert.id));
1190 }
1191 }
1192 None => {
1193 let id = new_id("mal", now);
1194 self.db
1195 .prepare("INSERT INTO margin_alerts (id, kind, subject, detail, since, opened_at) VALUES (?, ?, ?, ?, ?, ?)")
1196 .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()])?
1197 .run()
1198 .await?;
1199 kept.insert(id.clone());
Margin alerts measure what is sold, and say dollars when a percentage would mislead1200 // A workspace's is for Reach out, not the inbox.
1201 if kind != "workspace" {
1202 to_email.push(detail.clone());
1203 }
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1204 kept.insert(format!("email:{id}"));
1205 }
1206 }
1207 }
1208 for alert in &open {
1209 if !kept.contains(&alert.id) {
1210 self.db
1211 .prepare("UPDATE margin_alerts SET resolved_at = ? WHERE id = ?")
1212 .bind(&[stamp.as_str().into(), alert.id.as_str().into()])?
1213 .run()
1214 .await?;
1215 }
1216 }
1217 let to = env.var("COSTS_ALERT_EMAIL").map(|v| v.to_string()).unwrap_or_default();
1218 if !to_email.is_empty() && !to.trim().is_empty() {
1219 let subject = format!("[g1t costs] {} margin alert{}", to_email.len(), if to_email.len() == 1 { "" } else { "s" });
1220 match email_staff(env, to.trim(), &subject, &to_email).await {
1221 Ok(()) => {
1222 for marker in kept.iter().filter_map(|k| k.strip_prefix("email:")) {
1223 self.db
1224 .prepare("UPDATE margin_alerts SET emailed_at = ? WHERE id = ?")
1225 .bind(&[stamp.as_str().into(), marker.into()])?
1226 .run()
1227 .await?;
1228 }
1229 }
1230 Err(error) => worker::console_error!("could not email the margin alerts: {error}"),
1231 }
1232 }
1233 Ok(conditions.len() as u32)
1234 }
1235
1236 /// 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 mislead1237 /// Each day's cost shared out to comped workspaces.
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1238 async fn workspace_anomalies(&self, until: &str, settings: &CostSettings) -> Result<Vec<(String, i64, i64)>> {
1239 #[derive(Deserialize)]
1240 struct Row {
1241 workspace: String,
1242 cost: Option<i64>,
1243 revenue: Option<i64>,
1244 }
1245 let rows = self
1246 .db
1247 .prepare(format!(
Margin alerts measure what is sold, and say dollars when a percentage would mislead1248 // Against what its usage was priced at, not the cash it
1249 // paid: a trial or a gift paying for usage is not a price
1250 // below cost.
The workspace cost alert compares only days that carry their value, not the days before it was kept1251 // Days from before value_micros was kept have none: only days
1252 // since the first one that does are compared.
Margin alerts measure what is sold, and say dollars when a percentage would mislead1253 "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 kept1254 WHERE day >= ?1 AND day <= ?2 AND workspace NOT IN ({})
1255 AND day >= (SELECT MIN(day) FROM workspace_costs WHERE value_micros > 0)
1256 GROUP BY workspace",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1257 crate::sales::INTERNAL_SQL
1258 ))
1259 .bind(&[day_before(until, ANOMALY_DAYS - 1).into(), until.into()])?
1260 .all()
1261 .await?
1262 .results::<Row>()?;
1263 let rows: Vec<(String, i64, i64)> = rows.into_iter().map(|r| (r.workspace, r.cost.unwrap_or(0), r.revenue.unwrap_or(0))).collect();
1264 Ok(anomalies(&rows, settings.anomaly_factor, settings.anomaly_floor_micros))
1265 }
1266
1267 /// For Reach out: workspaces with an open cost-over-revenue alert,
1268 /// each with its detail and cost.
1269 pub(crate) async fn costing_more_than_they_pay(&self) -> Result<Vec<(String, String, i64)>> {
1270 let alerts = self
1271 .db
1272 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL AND kind = 'workspace' ORDER BY opened_at DESC LIMIT 50")
1273 .all()
1274 .await?
1275 .results::<AlertRow>()?;
1276 let mut out = Vec::new();
1277 for alert in alerts {
1278 #[derive(Deserialize)]
1279 struct Cost {
1280 cost: Option<i64>,
1281 }
1282 let cost = self
1283 .db
1284 .prepare("SELECT SUM(cost_micros) AS cost FROM workspace_costs WHERE workspace = ? AND day >= ?")
1285 .bind(&[alert.subject.as_str().into(), alert.since.as_str().into()])?
1286 .first::<Cost>(None)
1287 .await?
1288 .and_then(|c| c.cost)
1289 .unwrap_or(0);
1290 out.push((alert.subject, alert.detail, cost));
1291 }
1292 Ok(out)
1293 }
1294
1295 /// `admin_cost_alerts`: what sudo's banner says.
1296 pub(crate) async fn admin_cost_alerts(&self, _: AdminCostAlertsArgs) -> Result<Vec<MarginAlert>> {
1297 Ok(self
1298 .db
1299 .prepare("SELECT * FROM margin_alerts WHERE resolved_at IS NULL ORDER BY opened_at DESC LIMIT 50")
1300 .all()
1301 .await?
1302 .results::<AlertRow>()?
1303 .into_iter()
1304 .map(MarginAlert::from)
1305 .collect())
1306 }
1307
1308 /// `admin_run_costs`: the daily run, now.
1309 pub(crate) async fn admin_run_costs(&self, env: &Env, a: AdminRunCostsArgs) -> Result<Outcome<CostsRun>> {
1310 let keeper = crate::keeper::Keeper::from_env(env);
1311 let run = self.costs_daily(env, &keeper).await?;
1312 if !a.by.is_empty() {
1313 self.audit(
1314 "costs",
1315 "costs_run",
1316 &format!("{} lines, {} days, {} proposals, {} alerts", run.lines, run.days, run.proposals, run.alerts),
1317 &a.by,
1318 )
1319 .await?;
1320 }
1321 Ok(Outcome::Ok(run))
1322 }
1323
1324 /// `admin_set_cost_mapping`.
1325 pub(crate) async fn admin_set_cost_mapping(&self, a: AdminSetCostMappingArgs) -> Result<Outcome<CostMapping>> {
1326 let product = costs::slug(&a.product);
1327 let meter = if a.meter.trim() == "*" { "*".to_owned() } else { costs::slug(&a.meter) };
1328 if product.is_empty() || meter.is_empty() {
1329 return Ok(Outcome::fail(FailureCode::Invalid, "Name Cloudflare's product and a meter (or * for all of it)."));
1330 }
1331 let now = rfc3339(now_ms());
1332 if a.remove {
1333 self.db
1334 .prepare("DELETE FROM cost_map WHERE product = ? AND meter = ?")
1335 .bind(&[product.as_str().into(), meter.as_str().into()])?
1336 .run()
1337 .await?;
1338 self.audit("costs", "cost_mapping_removed", &format!("{product}/{meter}"), &a.by).await?;
1339 return Ok(Outcome::Ok(CostMapping {
1340 product,
1341 meter,
1342 bucket: String::new(),
1343 price_meter: None,
1344 own_meter: None,
1345 scale_to_own: false,
1346 drift_percent: 0.0,
1347 note: String::new(),
1348 updated_at: now,
1349 updated_by: a.by,
1350 }));
1351 }
1352 let bucket = costs::slug(&a.bucket);
1353 if bucket.is_empty() {
1354 return Ok(Outcome::fail(FailureCode::Invalid, "Say which of g1t's products it is a cost of."));
1355 }
1356 let clean = |v: Option<String>| v.map(|v| v.trim().to_owned()).filter(|v| !v.is_empty());
1357 let (price_meter, own_meter) = (clean(a.price_meter), clean(a.own_meter));
1358 let drift = a.drift_percent.filter(|d| d.is_finite() && *d > 0.0).unwrap_or(10.0);
1359 self.db
1360 .prepare(
1361 "INSERT INTO cost_map (product, meter, bucket, price_meter, own_meter, scale_to_own, drift_percent, note, updated_at, updated_by)
1362 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)
1363 ON CONFLICT (product, meter) DO UPDATE SET bucket = ?3, price_meter = ?4, own_meter = ?5, scale_to_own = ?6,
1364 drift_percent = ?7, note = ?8, updated_at = ?9, updated_by = ?10",
1365 )
1366 .bind(&[
1367 product.as_str().into(),
1368 meter.as_str().into(),
1369 bucket.as_str().into(),
1370 crate::optional(price_meter.as_deref()),
1371 crate::optional(own_meter.as_deref()),
1372 i32::from(a.scale_to_own).into(),
1373 drift.into(),
1374 a.note.trim().into(),
1375 now.as_str().into(),
1376 a.by.as_str().into(),
1377 ])?
1378 .run()
1379 .await?;
1380 self.audit("costs", "cost_mapping", &format!("{product}/{meter} → {bucket}"), &a.by).await?;
1381 Ok(Outcome::Ok(CostMapping {
1382 product,
1383 meter,
1384 bucket,
1385 price_meter,
1386 own_meter,
1387 scale_to_own: a.scale_to_own,
1388 drift_percent: drift,
1389 note: a.note.trim().to_owned(),
1390 updated_at: now,
1391 updated_by: a.by,
1392 }))
1393 }
1394
1395 /// `admin_costs`: the Costs & margin page.
1396 pub(crate) async fn admin_costs(&self, a: AdminCostsArgs, configured: bool) -> Result<CostsReport> {
1397 let until = rfc3339(now_ms())[..10].to_owned();
1398 let span = u64::from(a.days.unwrap_or(30).clamp(7, 90));
1399 let since = day_before(&until, span - 1);
1400 let days = self.margin_days(&since, &until).await?;
1401 let rules = self.rules().await?;
1402
1403 let mut products: BTreeMap<String, ProductMargin> = BTreeMap::new();
1404 let mut overall = OverallMargin::default();
1405 for d in &days {
1406 let p = products.entry(d.bucket.clone()).or_insert_with(|| ProductMargin {
1407 bucket: d.bucket.clone(),
1408 title: costs::bucket_title(&d.bucket),
1409 cost_source: if NOT_CLOUDFLARE.contains(&d.bucket.as_str()) { "ledger" } else { "cloudflare" }.into(),
1410 overhead: OVERHEAD.contains(&d.bucket.as_str()),
1411 ..ProductMargin::default()
1412 });
1413 p.cf_cost_micros += d.cf_cost_micros;
1414 p.own_cost_micros += d.own_cost_micros;
1415 p.value_micros += d.value_micros;
1416 p.cost_micros += d.cost();
1417 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 running1418 overall.given_micros += d.given.total();
1419 if NOT_CLOUDFLARE.contains(&d.bucket.as_str()) {
1420 overall.models_cost_micros += d.cost();
1421 } else {
1422 overall.cloudflare_cost_micros += d.cost();
1423 }
1424 overall.given_comped_micros += d.given.comped;
1425 overall.given_free_micros += d.given.free;
1426 overall.given_trial_micros += d.given.trial;
1427 overall.given_pool_micros += d.given.pool;
1428 let sold = (d.cost() - d.given.total()).max(0);
1429 if OVERHEAD.contains(&d.bucket.as_str()) {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1430 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 running1431 overall.running_cost_micros += sold;
1432 } else if d.bucket == UNMAPPED {
1433 overall.usage_micros += d.cash_micros;
1434 overall.unmapped_cost_micros += sold;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1435 } else {
1436 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 running1437 overall.usage_cost_micros += sold;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1438 }
1439 }
1440 for p in products.values_mut() {
1441 p.margin_micros = p.value_micros - p.cost_micros;
1442 p.margin_percent = margin_percent(p.value_micros, p.cost_micros);
1443 }
1444 let revenue = overall.usage_micros + overall.plans_micros;
1445 overall.margin_micros = revenue - overall.cost_micros;
1446 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 it1447 let sold = (overall.cost_micros - overall.given_micros).max(0);
1448 overall.sold_margin_micros = revenue - sold;
1449 overall.sold_margin_percent = margin_percent(revenue, sold);
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 running1450 overall.usage_margin_micros = overall.usage_micros - overall.usage_cost_micros;
1451 overall.usage_margin_percent = margin_percent(overall.usage_micros, overall.usage_cost_micros);
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1452 let mut products: Vec<ProductMargin> = products.into_values().collect();
1453 products.sort_by_key(|p| std::cmp::Reverse(p.cost_micros.max(p.value_micros)));
1454
1455 #[derive(Deserialize)]
1456 struct DriftRow {
1457 bucket: String,
1458 kind: String,
1459 ours: f64,
1460 cloudflare: f64,
1461 delta_percent: Option<f64>,
1462 detail: String,
1463 found_at: String,
1464 }
1465 let drift = self
1466 .db
1467 .prepare("SELECT * FROM cost_drift ORDER BY kind, bucket")
1468 .all()
1469 .await?
1470 .results::<DriftRow>()?
1471 .into_iter()
1472 .map(|r| CostDrift {
1473 title: costs::bucket_title(&r.bucket),
1474 bucket: r.bucket,
1475 kind: r.kind,
1476 ours: r.ours,
1477 cloudflare: r.cloudflare,
1478 delta_percent: r.delta_percent,
1479 detail: r.detail,
1480 found_at: r.found_at,
1481 })
1482 .collect();
1483
1484 #[derive(Deserialize)]
1485 struct Top {
1486 workspace: String,
1487 cost: Option<i64>,
1488 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 it1489 given: Option<i64>,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1490 internal: i64,
1491 }
1492 let top_workspaces = self
1493 .db
1494 .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 it1495 "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 daily1496 CASE WHEN workspace IN ({}) THEN 1 ELSE 0 END AS internal
1497 FROM workspace_costs WHERE day >= ?1 AND day <= ?2 GROUP BY workspace ORDER BY cost DESC LIMIT 15",
1498 crate::sales::INTERNAL_SQL
1499 ))
1500 .bind(&[since.as_str().into(), until.as_str().into()])?
1501 .all()
1502 .await?
1503 .results::<Top>()?
1504 .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 it1505 .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 daily1506 .collect();
1507
1508 #[derive(Deserialize)]
1509 struct Summary {
1510 source: String,
1511 product: String,
1512 meter: String,
1513 raw_name: String,
1514 unit: String,
1515 quantity: f64,
1516 cost_usd: f64,
1517 }
1518 let lines = self
1519 .db
1520 .prepare(
1521 "SELECT source, product, meter, MAX(raw_name) AS raw_name, MAX(unit) AS unit, SUM(quantity) AS quantity, SUM(cost_usd) AS cost_usd
1522 FROM cost_lines WHERE day >= ?1 AND day <= ?2 GROUP BY source, product, meter ORDER BY cost_usd DESC, product, meter LIMIT 200",
1523 )
1524 .bind(&[since.as_str().into(), until.as_str().into()])?
1525 .all()
1526 .await?
1527 .results::<Summary>()?
1528 .into_iter()
1529 .map(|l| CostLineSummary {
1530 bucket: costs::classify(&rules, &l.product, &l.meter).map(|r| r.bucket.clone()),
1531 product: l.product,
1532 meter: l.meter,
1533 raw_name: l.raw_name,
1534 unit: l.unit,
1535 source: l.source,
1536 quantity: l.quantity,
1537 cost_micros: micros(l.cost_usd),
1538 })
1539 .collect();
1540
1541 #[derive(Deserialize)]
1542 struct MapRow {
1543 product: String,
1544 meter: String,
1545 bucket: String,
1546 price_meter: Option<String>,
1547 own_meter: Option<String>,
1548 scale_to_own: i64,
1549 drift_percent: f64,
1550 note: String,
1551 updated_at: String,
1552 updated_by: String,
1553 }
1554 let mappings = self
1555 .db
1556 .prepare("SELECT * FROM cost_map ORDER BY product, meter")
1557 .all()
1558 .await?
1559 .results::<MapRow>()?
1560 .into_iter()
1561 .map(|m| CostMapping {
1562 product: m.product,
1563 meter: m.meter,
1564 bucket: m.bucket,
1565 price_meter: m.price_meter,
1566 own_meter: m.own_meter,
1567 scale_to_own: m.scale_to_own == 1,
1568 drift_percent: m.drift_percent,
1569 note: m.note,
1570 updated_at: m.updated_at,
1571 updated_by: m.updated_by,
1572 })
1573 .collect();
1574
1575 #[derive(Deserialize)]
1576 struct Fetched {
1577 at: Option<String>,
1578 }
1579 let fetched_at = self.db.prepare("SELECT MAX(fetched_at) AS at FROM cost_lines").first::<Fetched>(None).await?.and_then(|f| f.at);
1580
1581 Ok(CostsReport {
1582 configured,
1583 fetched_at,
1584 days: days
1585 .iter()
1586 .map(|d| CostDay {
1587 day: d.day.clone(),
1588 bucket: d.bucket.clone(),
1589 cf_cost_micros: d.cf_cost_micros,
1590 own_cost_micros: d.own_cost_micros,
1591 value_micros: d.value_micros,
1592 cash_micros: d.cash_micros,
1593 })
1594 .collect(),
1595 since,
1596 until,
1597 products,
1598 overall,
1599 drift,
1600 alerts: self.admin_cost_alerts(AdminCostAlertsArgs {}).await?,
1601 proposals: self.proposals().await?,
1602 versions: self.versions().await?,
1603 top_workspaces,
1604 lines,
1605 mappings,
1606 settings: self.cost_settings().await?,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1607 caps: self.spend_caps().await?,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1608 })
1609 }
1610}
1611
1612#[cfg(test)]
1613mod tests {
1614 use super::*;
1615
Margin alerts measure what is sold, and say dollars when a percentage would mislead1616 #[test]
Models' margin read -14%: usage nothing paid for is valued at price, not $01617 fn usage_nothing_paid_for_is_valued_at_price_and_paid_usage_at_what_was_paid() {
1618 // A free period: charged nothing, drawn from nothing.
1619 assert_eq!(usage_value(false, 1_000_000, 0, 20), 1_200_000);
1620 // Charged, or drawn from a trial: what was paid.
1621 assert_eq!(usage_value(false, 1_000_000, 1_200_000, 20), 1_200_000);
1622 assert_eq!(usage_value(false, 1_000_000, 900_000, 20), 900_000);
1623 // g1t's own: at price.
1624 assert_eq!(usage_value(true, 1_000_000, 0, 20), 1_200_000);
1625 // No cost, nothing paid: nothing.
1626 assert_eq!(usage_value(false, 0, 0, 20), 0);
1627 }
1628
1629 #[test]
Margin alerts measure what is sold, and say dollars when a percentage would mislead1630 fn the_overall_alert_says_dollars_while_little_comes_in() {
1631 let small = overall_detail(90_000, 7_500_000, 3, 10.0, -8239.7);
1632 assert!(small.contains("took in $0.09 against $7.50"), "{small}");
1633 assert!(!small.contains('%'), "{small}");
1634 let real = overall_detail(30_000_000, 40_000_000, 3, 10.0, -33.3);
1635 assert!(real.contains("as low as -33.3%"), "{real}");
1636 }
1637
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1638 fn rule(product: &str, meter: &str, bucket: &str, own: Option<&str>) -> Rule {
1639 Rule { product: product.into(), meter: meter.into(), bucket: bucket.into(), price_meter: None, own_meter: own.map(Into::into), drift_percent: 10.0 }
1640 }
1641
1642 fn rules() -> Vec<Rule> {
1643 vec![
1644 rule("containers", "*", "sandboxes", None),
1645 rule("workers", "*", "platform", None),
1646 rule("artifacts", "*", "git", Some("git_operations")),
1647 rule("artifacts", "events_", "git", Some("git_operations")),
1648 ]
1649 }
1650
1651 fn revenue_map() -> BTreeMap<String, String> {
1652 [("sandbox", "sandboxes"), ("git", "git"), ("plan", "platform")].iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()
1653 }
1654
1655 fn line(day: &str, source: &str, product: &str, meter: &str, quantity: f64, cost: f64) -> LineRow {
1656 LineRow { day: day.into(), source: source.into(), product: product.into(), meter: meter.into(), quantity, cost_usd: cost }
1657 }
1658
1659 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 running1660 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 daily1661 }
1662
1663 #[test]
1664 fn a_day_puts_the_bill_g1ts_counts_and_charges_side_by_side() {
1665 let lines = vec![
1666 line("2026-10-15", SOURCE_BILLABLE, "containers", "container_memory", 1000.0, 2.00),
1667 line("2026-10-15", SOURCE_BILLABLE, "artifacts", "artifacts_operations", 30_000.0, 3.00),
1668 // Artifacts' own events: not used while the bill has a count.
1669 line("2026-10-15", SOURCE_ARTIFACTS, "artifacts", "events_pull", 29_000.0, 0.0),
1670 line("2026-10-15", SOURCE_BILLABLE, "workers", "workers_cpu_ms", 1.0, 0.50),
1671 line("2026-10-15", SOURCE_BILLABLE, "browser_rendering", "browser_hours", 2.0, 0.25),
1672 ];
1673 let own = vec![
1674 OwnRow { day: "2026-10-15".into(), meter: "git_operations".into(), workspace: "acme".into(), quantity: 7_500.0 },
1675 OwnRow { day: "2026-10-15".into(), meter: "git_operations".into(), workspace: "beta".into(), quantity: 2_500.0 },
1676 ];
1677 let usage = vec![
1678 usage("2026-10-15", "acme", "sandbox", 2_400_000, 1_000_000, 2_000_000),
1679 usage("2026-10-15", "beta", "sandbox", 1_200_000, 1_200_000, 1_000_000),
1680 usage("2026-10-15", "acme", "git", 600_000, 600_000, 500_000),
1681 usage("2026-10-15", "acme", "implement", 120_000, 120_000, 100_000),
1682 usage("2026-10-15", "beta", "plan", 20_000_000, 20_000_000, 0),
1683 ];
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 running1684 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 daily1685 let get = |bucket: &str| days.iter().find(|d| d.bucket == bucket).unwrap();
1686 let sandboxes = get("sandboxes");
1687 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));
1688 let git = get("git");
1689 assert_eq!(git.cf_cost_micros, 3_000_000);
1690 assert_eq!((git.cf_quantity, git.own_quantity), (30_000.0, 10_000.0));
1691 assert_eq!(get("platform").value_micros, 20_000_000);
1692 // Not mapped: a leak until someone maps it.
1693 assert_eq!(get(UNMAPPED).cf_cost_micros, 250_000);
1694 // Models: no Cloudflare line, their cost is g1t's own.
1695 assert_eq!(get("models").cost(), 100_000);
1696 // Git's cost shared by g1t's own counts (Cloudflare gave none per
1697 // workspace here): three quarters to acme.
1698 let share = |ws: &str, bucket: &str| workspaces.iter().find(|w| w.workspace == ws && w.bucket == bucket).map(|w| (w.cost, w.revenue));
1699 assert_eq!(share("acme", "git"), Some((2_250_000, 600_000)));
1700 assert_eq!(share("beta", "git"), Some((750_000, 0)));
1701 // Every bucket's cost is shared out exactly.
1702 for d in &days {
1703 let shared: i64 = workspaces.iter().filter(|w| w.bucket == d.bucket).map(|w| w.cost).sum();
1704 assert_eq!(shared, d.cost(), "{}", d.bucket);
1705 }
1706 }
1707
1708 #[test]
1709 fn artifacts_events_count_when_the_bill_does_not() {
1710 let lines = vec![
1711 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_pull", 120.0, 0.0),
1712 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_push", 30.0, 0.0),
1713 line("2026-10-05", SOURCE_ARTIFACTS, "artifacts", "events_ratelimited", 9.0, 0.0),
1714 ];
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 running1715 let (days, _) = fold(&rules(), &revenue_map(), &lines, &[], &[], &BTreeSet::new());
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1716 assert_eq!(days[0].cf_quantity, 150.0);
1717 assert_eq!(days[0].cf_cost_micros, 0);
1718 }
1719
1720 #[test]
1721 fn month_end_meters_are_told_by_the_day_from_snapshots() {
1722 let snap = |day: &str, cost: i64, charge: i64| (day.to_string(), "acme".to_string(), "git".to_string(), cost, charge);
1723 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)]);
1724 assert_eq!(
1725 rows.iter().map(|r| (r.day.as_str(), r.cost, r.value)).collect::<Vec<_>>(),
1726 vec![("2026-10-30", 100, 120), ("2026-10-31", 150, 180), ("2026-11-01", 40, 48)]
1727 );
1728 }
1729
1730 #[test]
1731 fn a_plan_payment_is_spread_over_the_month_it_pays_for() {
1732 let days = spread("2026-10-01T00:00:00.000Z", 20_000_000, 30);
1733 assert_eq!(days.len(), 30);
1734 assert_eq!(days[0], ("2026-10-01".to_string(), 666_667));
1735 assert_eq!(days[29], ("2026-10-30".to_string(), 666_666));
1736 assert_eq!(days.iter().map(|d| d.1).sum::<i64>(), 20_000_000);
1737 assert!(spread("2026-10-01", 0, 30).is_empty());
1738 assert_eq!(dollars(17_024_000), "$17.02");
1739 assert_eq!(dollars(-27_668_620), "-$27.67");
1740 assert_eq!(dollars(63_000), "$0.063");
1741 }
1742
1743 #[test]
1744 fn margins_and_deltas() {
1745 assert_eq!(margin_percent(1_200_000, 1_000_000).map(|m| (m * 100.0).round() / 100.0), Some(16.67));
1746 assert_eq!(margin_percent(0, 5), None);
1747 assert_eq!(delta_percent(110.0, 100.0), Some(10.0));
1748 assert_eq!(delta_percent(1.0, 0.0), None);
1749 }
1750
1751 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 running1752 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 daily1753 }
1754
1755 #[test]
1756 fn counts_more_than_the_threshold_apart_are_drift() {
1757 // Cloudflare counted 30,000 operations where g1t counted 10,000:
1758 // binding reads, perhaps. -66.7%.
1759 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);
1760 assert_eq!(drift.iter().map(|d| d.kind).collect::<Vec<_>>(), vec![DriftKind::Count, DriftKind::Cost]);
1761 assert!((drift[0].delta_percent.unwrap() + 66.666).abs() < 0.01);
1762 // 9% apart: within 10%.
1763 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());
1764 // Uncounted products have no count drift.
1765 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());
1766 }
1767
1768 #[test]
1769 fn cost_with_no_revenue_is_a_leak_but_not_for_running_g1t() {
1770 let leak = drifts("actions_cache", &[day("actions_cache", 400_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000);
1771 assert_eq!(leak.len(), 1);
1772 assert_eq!(leak[0].kind, DriftKind::Leak);
1773 assert!(drifts("platform", &[day("platform", 5_000_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
1774 // Pennies say nothing.
1775 assert!(drifts("actions_cache", &[day("actions_cache", 50_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000).is_empty());
1776 assert!(drifts(UNMAPPED, &[day(UNMAPPED, 250_000, 0, 0, 0.0, 0.0)], 10.0, false, 100_000)[0].kind == DriftKind::Leak);
1777 }
1778
1779 #[test]
1780 fn a_margin_alert_needs_n_days_in_a_row_under_the_floor() {
1781 let s = |d: &str, revenue: i64, cost: i64| (d.to_string(), revenue, cost);
1782 // 5%, 0%, -20%: three days under 10%.
1783 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)];
1784 let (from, worst) = breach(&series, 10.0, 3, 100_000).unwrap();
1785 assert_eq!(from, "10-14");
1786 assert!((worst + 20.0).abs() < 1e-9);
1787 // A good day in the window clears it.
1788 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)];
1789 assert!(breach(&mended, 10.0, 3, 100_000).is_none());
1790 // Cost with no revenue at all is the worst margin there is.
1791 assert_eq!(breach(&[s("10-16", 0, 500_000)], 10.0, 1, 100_000).unwrap().1, -100.0);
1792 // Too little cost to judge.
1793 assert!(breach(&[s("10-16", 0, 5_000)], 10.0, 1, 100_000).is_none());
1794 assert!(breach(&series, 10.0, 9, 100_000).is_none());
1795 }
1796
1797 #[test]
1798 fn shared_costs_add_up_to_the_bill() {
1799 let w = |k: &str, v: f64| (k.to_string(), v);
1800 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)]);
1801 assert_eq!(attribute(10, &[w("a", 3.0), w("b", 1.0), w("a", 0.0)]), vec![("a".into(), 8), ("b".into(), 2)]);
1802 assert!(attribute(10, &[w("a", 0.0)]).is_empty());
1803 assert!(attribute(0, &[w("a", 1.0)]).is_empty());
1804 }
1805
1806 #[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 it1807 fn what_g1t_gives_away_is_kept_apart_from_what_it_sells() {
1808 let map = BTreeMap::new();
1809 // A comped workspace (all of it given), one in its trial (half paid
1810 // 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 running1811 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 it1812 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 running1813 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 it1814 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 running1815 // Nothing priced that day: free use.
1816 let free = usage("2026-10-15", "gamma", "agent", 0, 0, 1_000_000);
1817 let internal = BTreeSet::from(["flagon".to_string()]);
1818 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 it1819 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 running1820 assert_eq!(models.cost(), 4_000_000);
1821 assert_eq!(models.given, Given { comped: 1_000_000, free: 1_000_000, trial: 500_000, pool: 0 });
1822 let given = |w: &str| workspaces.iter().find(|x| x.workspace == w).unwrap().given.total();
1823 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 it1824 }
1825
1826 #[test]
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1827 fn a_workspace_that_costs_more_than_it_pays_is_flagged() {
1828 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)];
1829 let found = anomalies(&rows, 1.0, 1_000_000);
1830 assert_eq!(found, vec![("acme".to_string(), 5_000_000, 1_000_000)]);
1831 // At twice its revenue as the threshold, $5 against $3 is fine.
1832 assert!(anomalies(&[("acme".to_string(), 5_000_000, 3_000_000)], 2.0, 1_000_000).is_empty());
1833 }
1834
1835 #[test]
1836 fn a_git_operation_costs_what_cloudflare_counts_for_it() {
1837 // $0.15 per 1,000 of Cloudflare's operations, on the charged days.
1838 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();
1839 assert!((rate - 0.000_15).abs() < 1e-12);
1840 // Cloudflare counted 3 for every 1 g1t did: binding reads count.
1841 let per_op = derived_unit_cost(rate, 300_000.0, 100_000.0).unwrap();
1842 let per_thousand_micros = per_op * unit_size("1,000 operations") * 1e6;
1843 assert!((per_thousand_micros - 450_000.0).abs() < 1e-6, "{per_thousand_micros}");
1844 // Too few of g1t's units to say.
1845 assert!(derived_unit_cost(rate, 3_000.0, 500.0).is_none());
1846 assert!(billed_rate(&[(10_000.0, 0.0)]).is_none());
1847 assert_eq!(unit_size("million requests"), 1e6);
1848 assert_eq!(unit_size("second"), 1.0);
1849 }
1850}