# Cost & attribution

Your bill tripled last month. Find out which team, feature or customer did it, and how much to trust the answer.

Source: https://tokentriage.com/docs/build/cost-analytics

---
import Callout from '../../../components/Callout.astro';
import Details from '../../../components/Details.astro';
import NextSteps from '../../../components/NextSteps.astro';
import CropShot from '../../../components/CropShot.astro';

Someone forwards you the provider invoice with one line of commentary: *this is three times
last month, what happened?* You have an hour. The invoice groups by model, which tells you
that most of it went to your most expensive model, which you already knew. It cannot tell you
which team, which feature, or which customer sent those requests, because the provider never
knew.

That gap is the whole subject of this section. A provider bills an API key. You need to bill a
decision someone in your organisation made. Nothing in between records the connection unless
something is sitting in the request path writing it down.

TokenTriage writes one costed row per request, and everything here is an aggregation of those
rows. What makes the aggregation worth reading is the second half of the promise: every figure
says how much to trust it. A total names the rows it could not price rather than counting them
as free. A saving says whether it was measured or modelled. A recommendation that cannot
support its own number prints the number it would have needed instead.

## The hour you have

Here is the order that answers the question fastest, with the page that covers each step.

1. **Look at what already fired.** If spend jumped, the detector has probably already flagged
   the hour and ranked what drove it. [Anomaly detection](/docs/build/anomaly-detection).
2. **Split the total by something meaningful.** Model, agent, step class or trace, from the
   terminal, in one command. [Read your spend from the terminal](/docs/build/cost-cli).
3. **Split it by *your* nouns**: team, tenant, feature, customer. This is the step that needs
   configuration you may not have turned on yet.
   [How a dollar gets a name](/docs/build/cost-attribution).
4. **Check the figure before you send it on.** Which rows were excluded, whether the number is
   measured or modelled. [How to read a cost figure](/docs/build/cost-figures).
5. **Tie it back to the invoice**, and see what the two sides disagree about.
   [Reconcile against a provider invoice](/docs/build/cost-reconciliation).

<CropShot
  stem="cost-attribution"
  alt="A cost breakdown attributing spend across tenants and models, each figure carrying its provenance and an excluded-row count."
  caption="Spend split across attribution dimensions, each figure carrying the rows it could not cover."
/>

## What is on by default, and what is not

This matters more than usual here, because two of the defaults decide whether the section's
best surfaces exist for you at all.

| Thing | Default | What you lose without it |
|---|---|---|
| The costed ledger row | on | nothing: every proxied request is costed and logged |
| `top` and `report` | on | nothing: they read the log directly, no setup |
| Anomaly detection | with the dashboard | nothing beyond turning the dashboard on |
| `ledger.dimensions.enabled` | **off** | team, tenant, feature and per-customer attribution |
| `analytics.enabled` | **off** | rollups, recommendations, forecasts, chargeback, exports |
| `dashboard.index.enabled` | off | the index that analytics is built on |

A fresh install costs everything and can group by less than you expect. It knows the model, the
tier, the provider, the endpoint, and whatever trace identity your client sends. It does not
know your tenants, because nothing on the wire told it.
[Turn on business dimensions](/docs/build/cost-dimensions) is the ten-minute fix, and it is
worth doing before you need it, because dimensions apply to rows written after you turn them
on and are not applied retroactively.

<Callout type="key">
Attribution comes only from explicit identity in the request headers. TokenTriage does not
infer which tenant or agent a request belongs to from timing, prompt prefixes or session
heuristics. A ledger that guesses looks complete and is wrong, which is worse than one that is
narrow and says so.
</Callout>

## The two ways a figure is produced

Every number in this section comes from one of two paths, and knowing which changes what you
can ask.

**The decision log**, a JSONL file, is the record. `top` and `report` read it directly with no
database, no index and no configuration. That is the whole of the terminal experience, and it
survives losing everything else.

**The derived index** is a SQLite file rebuilt from that log. It carries an hourly
pre-aggregation on eight attribution dimensions, which is what makes a month-scale question
finish quickly, and it is what every dashboard cost surface, export and detector reads. Delete
it at any time and rebuild it from the log.

Both answer the same question with the same number. That is the constraint the section is built
on, and [what the rollups make cheap](/docs/build/cost-rollups) explains where the
pre-aggregation helps, where it silently steps aside, and the two dimensions it leaves out for
good.

## What this section covers

The pages fall into four groups.

**Attribution**, where a dollar's name comes from.
[How a dollar gets a name](/docs/build/cost-attribution) explains the three authorities behind
a row's dimensions and why two of them are not interchangeable.
[Turn on business dimensions](/docs/build/cost-dimensions) is the configuration.
[What the rollups make cheap](/docs/build/cost-rollups) covers the pre-aggregation and its
limits.

**Trust**, how much a figure is worth.
[How to read a cost figure](/docs/build/cost-figures) teaches the vocabulary as it appears on
cost surfaces, and [verdicts, methods and baselines](/docs/build/cost-figure-reference) is the
lookup table behind it.

**Action**, what to do about it.
[Recommendations](/docs/build/cost-optimization) covers what the engine proposes and what it
refuses to propose, [the eight recommendation types](/docs/build/cost-recommendation-types)
lists them, and [the realized measurement](/docs/build/cost-realized) is the only thing on the
site that produces a measured saving.
[Anomaly detection](/docs/build/anomaly-detection) watches for spend that broke pattern.

**Settlement**, getting the number out of the building.
[Reconcile against a provider invoice](/docs/build/cost-reconciliation),
[forecast spend](/docs/build/cost-forecasting),
[chargeback, showback and FOCUS exports](/docs/build/cost-exports), and
[what the measurement itself costs](/docs/build/cost-metacost).

<Details summary="What this section does not cover, and where that material lives">

**Limits and refusals.** Everything about capping spend belongs to
[governance](/docs/build/governance): budgets, rate limits, and what happens when one is hit.
The division is enforcement versus reporting. Governance decides whether a request goes
through; this section reports what the ones that did went on. A budget that was passed is an
enforcement property, and a spend report is ours.

**Ledger field definitions.** Every field on a costed row, with its type and when it is absent,
is in [decision ledger fields](/docs/reference/ledger-fields).

**Where the prices come from.** The pricing snapshot behind a figure, the catalog key the
price resolved under, and the `estimated` and `unpriced` flags are defined field by field in
[the cost block of a ledger row](/docs/reference/ledger-fields#cost).

**Cache savings arithmetic.** The provider's prompt cache and TokenTriage's response cache
produce two savings figures that are kept apart, and the reasoning is in
[two kinds of cache savings](/docs/concepts/cache-accounting).

**The verdict vocabulary's definitions.** [The honesty model](/docs/concepts/honesty-model)
owns them. This section teaches how they show up on cost surfaces and links there for the
rules.

</Details>

## Where it can go wrong

The most expensive mistake in this section is not a wrong number. It is a right number read as
though it covered everything.

A total is computed over the rows it could price. If your ledger contains a model your price
table has no entry for, such as a fine-tuned model or a provider added last week, its
rows are excluded and counted, and the count is printed beside the figure:

```text
COST excludes 35 unpriced rows of 412 (no price resolved; the $0 is a missing price, not $0 of spend)
```

Read that line before you read the dollar above it. Thirty-five unpriced rows out of four
hundred is a total you can send on with a caveat. Thirty-five out of forty is not a total at
all. The same rule holds on every surface here: exports leave the cell empty, the API sends
`null`, and no path anywhere turns an unpriceable row into `$0.00`.

<NextSteps items={[
  {title: "How a dollar gets a name", href: "/docs/build/cost-attribution", description: "The three authorities behind a row's dimensions, and why a stamped one and an asserted one are not the same evidence."},
  {title: "Read your spend from the terminal", href: "/docs/build/cost-cli", description: "top and report over the decision log: five groupings, the cost percentiles, and the columns that mislead."},
  {title: "Turn on business dimensions", href: "/docs/build/cost-dimensions", description: "The ten-minute change that lets you group spend by team, tenant, feature and customer."},
  {title: "How to read a cost figure", href: "/docs/build/cost-figures", description: "Verdicts, baselines and exclusion counts, as they appear on the surfaces you will actually be looking at."},
]} />
