Live Demo: Meter

A month of usage from an invented AI writing product runs through the Precomputing Meter, inside SQLite, right here in your browser. Six customers call three models through two gateways, and every request is reported to one meter. Retries arrive twice. A link goes down for six hours, and a queue sticks at the month’s end. The meter counts each request once, in the hour it happened, and September’s invoices come out exact.

Simulated usage, real meter. The customers, prices and requests are invented and follow a fixed script. The meter is a compiled Precomputing policy running in SQLite’s own WebAssembly build, with the billing tables in the same file.

How to Run It

  1. Press Play. September starts. The month passes in about a minute, slowing down when something happens.
  2. Make trouble. Start a retry storm, or cut the eu gateway’s link to the meter, and watch the refused reports and the hourly chart.
  3. Review the results. The month finishes and closes. Every invoice is checked against a recount of the gateways’ reports.
  4. Ask the meter. Run a ready-made SQL question or write your own, then download the file.

On a wide screen the demo can use the whole window: open it full screen.

The Controls

Control What it does
Play, Pause, Resume Starts the month, pauses it and carries on. An uninterrupted month takes about a minute
Stop Ends the run and goes back to 1 September
Review the results Finishes the month at full speed, lets it close, then checks every invoice
Retry storm For the next hour every request is reported three times, through either gateway
Cut the eu link The eu gateway loses its link to the meter for 12 hours. It keeps serving and holds its reports
Raise Juniper’s quota Once Juniper Bakery Blog has used its Free quota, raises its limit so the gateway serves it again
3 days, Month Shows the last three days of the hourly chart, or the whole month
Policy, Compiled SQL, Billing SQL, Try the compiler Show the meter’s policy, its SQL, the billing tables beside it, and a box to compile a changed policy
Run Runs your SQL against the meter while the month is paused or finished

The Month

Customer Plan Gateway Requests an hour Models
Sundial Research Enterprise, 25% off list us About 210 Small, medium and large
Quarry Road Media Pro us About 130 Mostly medium
Maple Grove Travel Pro us About 85 Mostly small
Harbor Legal Drafts Pro eu About 55 Medium and large
Juniper Bakery Blog Free, 5 million tokens a month eu About 7 Mostly small
Northgate Tutors Free, 5 million tokens a month eu About 2 Small

Pro has a quota of 300 million tokens a month; Enterprise has none. Example list prices per million tokens, in and out: small $0.30 and $1.20, medium $2.50 and $10, large $12 and $48. Model cost is half of list. All invented.

About 2% of requests get no answer in time and are sent again, with the same request id, through either gateway. On top of that the script plants four events:

  • 15 September, 08:00 to 14:00. The eu gateway loses its link to the meter for six hours, keeps serving, and delivers the 625 reports it held when the link returns.
  • 27 September. Juniper Bakery Blog reaches its Free quota, and the eu gateway turns its requests away until October.
  • Around midnight on 30 September. The eu gateway is slow, so some September requests reach the meter in October.
  • 2 October, 05:00. A queue stuck in the us gateway since 30 September is emptied, five hours after September closed.

The Policy

stream usage exact {
  id     request_id refuse repeats 7d     # a retried request is counted once
  key    customer text
  key    model text
  key    gateway text
  value  input_tokens integer
  value  output_tokens integer
  derive tokens = input_tokens + output_tokens

  late   48h                              # up to two days late still counts, in the month it happened,
  period month close 24h                  # unless that month has closed: a month closes a day after it ends
  raw    until closed + 90d               # every request kept until its month has been closed 90 days
  rollup 1h keep 400d
  rollup 1d keep forever
}

precompute requests_month = count(usage) by customer, model per month
precompute input_month    = sum(usage.input_tokens) by customer, model per month
precompute output_month   = sum(usage.output_tokens) by customer, model per month

precompute tokens_month   = sum(usage.tokens) by customer per month
quota monthly_tokens = tokens_month

The invoices are a view over the precomputes and a price list kept in the same file, with money in billionths of a dollar as integers, so every sum is exact and rounding to the cent happens once, at the end.

What the Numbers Mean

  • Requests metered: reports the meter counted, one per request. A retried report of a request already counted is refused, so no request counts twice.
  • Retried reports refused: reports whose request id the meter had already counted in the last seven days.
  • September revenue so far: the invoices as they stand, read from the precomputes with one SQL view.
  • Gross margin after model costs: revenue minus what the product pays for the models, as a share of revenue.
  • The quota bar: the monthly_tokens view, which each gateway reads once a minute before it serves. A read is one lookup by primary key.
  • What the meter refused: every refused report, counted by reason in usage_refused. A report refused as closed is money known to be missing, to the request.

Things to Try

  1. Let the month finish untouched. Press Play and wait, or Review the results at once. September’s invoices come to $5,804.56 against $3,337.84 of model cost, and every line matches the recount.
  2. Start a retry storm. For an hour every request is reported three times. The refused count jumps, the invoices do not.
  3. Cut the eu link. The eu gateway’s hourly chart shows a gap. When the link returns, the held reports arrive and the gap fills in, because each request counts in the hour it happened.
  4. Watch Juniper’s quota. Late in the month its bar fills and the gateway turns requests away. Raise the quota and it is served again; the requests turned away were never served, so they are never billed.
  5. Wait for the stuck queue. On 2 October, 642 reports arrive after September has closed. The meter refuses every one, the refusal count says exactly what was missed, and the invoices sent on the 2nd stay true.
  6. Ask the meter. Try “Reconcile with every request”, which sets each invoice line beside the same totals recomputed from the requests kept whole, or “Margin by customer”.

If It Does Not Start

The demo works in any current Chrome, Edge, Firefox or Safari, on a computer or a phone, with JavaScript switched on. It needs WebAssembly, which all of them support. SQLite comes with the page, 1.5 MB (577 KB compressed), and runs inside it. If the demo says it could not start, try another browser, or allow scripts on this page if an extension blocks them.

In testing no check has failed. If one ever does, the results say so in red, and the project would be glad to hear about it through the contact page.

What Is Real Here

Real:

  • The meter: the compiled policy, from the real compiler, in SQLite’s own WebAssembly build.
  • The billing tables and views, and every invoice amount, to the billionth of a dollar.
  • The checks: separate code takes the gateways’ reports in the order they were sent, applies the policy’s rules itself and never reads the meter.

Simulated:

  • The product, its customers, plans, prices and requests, and the two gateways.
  • Time: a month passes in about a minute.

The native Engine takes the same month’s reports in 2.3 to 3.3 seconds and writes the same values in every table: see the Platform page. The AI usage billing case study follows the month.