> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brussle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Per-customer corrections

> Run the same judgments for many customers from a template: each customer reads the shared correction from its first answer, and on Team and Scale gets its own correction once its own outcomes clearly say otherwise.

If you run the same judgments for many customers, each in its own namespace under a [template](/guides/templates), Brussle corrects every customer from its first answer with the correction pooled across all of them. On Team and Scale, a customer with enough outcomes of its own also gets its own correction. That correction is held toward the shared one until the customer's outcomes clearly say otherwise, and is kept or replaced by the same rule as any fit. The report says which correction each customer reads, and why.

Here a customer of yours is a **tenant**, a namespace that inherits the judgment from a template's prefix.

## The pooled correction

Tenants post [outcomes](/calibration/outcomes) on their own namespace paths, never on the prefix, and the correction on the prefix pools them. Brussle makes one fit for each template version and engine epoch, fitted each night across every tenant's outcomes, and the template's run makes every tenant's fit at the same time.

* **A tenant without its own fit reads the pooled fit,** so Brussle corrects a tenant you create today from its first answer. The pooled fit was made on other tenants' outcomes, so it is not yet measured on this one. Once the tenant posts outcomes, the report on its own path measures what it reads against them.
* **Tenants under a [non-production prefix](/guides/staging-environments#what-it-changes),** such as `acme/staging/`, read the pool but add nothing to it and get no fit of their own, unless the template itself is under that prefix.
* **Settings live on the template,** so you set [implicit negatives](/calibration/horizons#turn-on-implicit-negatives), [pins](#pin-a-fit-for-every-tenant), promotions and [named runs](/calibration/fits#fit-on-outcomes-you-choose) on the prefix path. A tenant that sets `calibration`, promotes or makes a named run gets `invalid_request`. Neither the prefix nor a tenant can set [outcome rules](/calibration/outcomes#rule-limits).
* **The list of fits** on a tenant's path shows the template's fits, since those are what its answers read.
* **A new version** starts each tenant on that version's pool again. Tenants keep following the template, and you do not detach anything.
* **A composite** keeps one pooled combiner for all tenants.

## Each tenant grows its own correction (Team and Scale)

A tenant's data can differ from the pool's (another language, a stricter review team, another base rate). So on Team and Scale, a tenant with 50 outcomes of its own in an epoch, 15 of each kind, also gets its own fit. Below that it reads the pool.

* **It starts at the pool's fit** and moves toward the tenant's own outcomes as they grow, `n / (n + 100)` of the way on `n` outcomes. That is one third of the way at 50 and a half at 100. The report shows this as `weight`, and each corrected answer shows it as `prior` with `kind: pool`.
* **It is used only when it is clearly better** than what the tenant would read otherwise (the pool or raw), on tenant outcomes that the fit did not see. Until then the tenant reads the pool, or raw if the pool does not beat raw.
* **It is kept by the same rule as the pool's.** Brussle fits the tenant again each night, and the new fit replaces the one the tenant reads only when it is clearly better on the tenant's own outcomes since, and moves its numbers by at least 0.01. When the pool beats the tenant's current fit by the same margin on those outcomes, the tenant goes back to the pool. See [the rule](/calibration/promotion#the-rule).
* **When the pool's fit changes, the pool part of each tenant's blend changes with it.** The pool is tested on every tenant's outcomes, where one tenant is a small part. Each tenant's report the next night shows the new blend against the pool, in `tenant.current.since`.
* **A promote on the template** (`POST .../calibration/fit` with `{"promote": true}` on the prefix path) makes the newest fit current for the pool and every tenant.
* **Plans.** Below Team, each tenant reads the pool. After a downgrade takes effect the next fit puts each tenant back on the pool, and after an upgrade the next fit gives tenants their own fits.

### Its own weights over features

A count of open tickets can mean less in one tenant than across the pool. So on a `bool` with [features](/calibration/features), a tenant's own fit has its own weights over the engine's `p` and the features, from 100 of its own outcomes with 20 of each kind. Each weight starts at the pool's, moves toward what the tenant's outcomes show by the same `n / (n + 100)`, and is kept by the same rule (a feature that none of the tenant's documents has keeps the pool's weight). The tenant's `p` is then its own fit over the answer's `raw.p` and features, and the answer's `fit` has `"tenant": true` and the tenant's own `id`.

A `choice` or `score` with features reads the pooled fit in every tenant.

### Which readers are judged again

On a judgment with features, readers act on `p`. When one tenant's own fit changes, Brussle judges again the [readers](/guides/roll-ups) in that tenant only. When the pooled fit changes, Brussle judges again the readers in the tenants that read the pool, since the pool does not change a tenant that reads its own fit.

### The interval on a tenant

When a tenant reads its own fit blended with the pool, the [interval](/calibration/correction#how-sure-a-corrected-number-is) of each corrected number is the same blend of its own fit's interval and the pool's, widened to hold its own fit's interval. The pool pulls the number toward the other tenants. The interval does not hide that: it is never narrower than the tenant's own outcomes support. A tenant that reads the pool reads the pool's interval, and on a `bool` with features, a tenant that reads its own fit reads its own fit's interval.

The corrected number on a tenant that reads a fit of its own blends the tenant's fit with the template's fit that `fit` names. [A fit's formula](/calibration/fits#read-the-formula-of-a-fit) is the template's, not the tenant's own.

## Pin a fit for every tenant

A [pin](/calibration/promotion#pin-a-fit) holds one pooled fit for one version and epoch, and you set it on the prefix path with `PATCH` and `calibration`, as on a namespace.

* **Each tenant reads the pinned fit** for that version and epoch, including a tenant that had its own. While the pin holds, no tenant gets its own fit for it, and each tenant's report shows `tenant.reason` `pinned`.
* **Other versions and epochs** do not change, and tenants keep their own fits there.
* **On a `bool` with features,** the readers are those of every tenant that inherits the judgment. The `PATCH` returns their cost in `downstream`, from up to 100 tenants and scaled to all of them, as for a [threshold change](/guides/roll-up-rules#changing-a-threshold-a-reader-reads). With `confirm`, one `resync` job judges again the readers whose view of the judgment changes.
* **When you lift the pin,** Brussle brings the next run forward, and on Team and Scale that run can give tenants their own fits again.

## Read the report on a tenant

The [report](/calibration/report) and threshold recommendations use the pooled outcomes on the prefix path. On a tenant's path they use that tenant's outcomes, and each epoch's `tenant` says what the tenant reads:

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{
  "tenant": {
    "applied": "tenant_shrunk",
    "reason": "tenant_better",
    "message": "This tenant's own fit, blended with the template's pool, did best on its held-out outcomes, and clearly better than the pool, so its answers read it.",
    "outcomes": 3000,
    "weight": 0.968,
    "held_out": {"raw_log_loss": 0.61, "pooled_log_loss": 0.55, "tenant_log_loss": 0.42}
  }
}
```

On a `bool` with features, `tenant` also has `method` and `weights`:

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{
  "tenant": {
    "applied": "tenant_shrunk",
    "reason": "tenant_better",
    "method": "features",
    "outcomes": 412,
    "weight": 0.805,
    "held_out": {"raw_log_loss": 0.61, "pooled_log_loss": 0.48, "tenant_log_loss": 0.41},
    "weights": [
      {"input": "engine", "pool": 1.12, "tenant": 1.08},
      {"input": "tickets.count", "pool": 0.42, "tenant": 0.81}
    ]
  }
}
```

* **`applied`** is `tenant_shrunk` (the tenant's own fit, held toward the pool's), `pooled` or `raw`.
* **`weight`** is how far the tenant's own fit moves from the pool's toward its own outcomes, `n / (n + 100)`.
* **`method`**, on a `bool` with features only, is `features`, which means the tenant has its own weights over the features.
* **`weights`**, on a `bool` with features only, gives each input's weight under the pool's fit and the tenant's own, side by side (first the engine's `p` as `engine`, then each feature). The weights share one scale across the template, so you can compare inputs in different units. The difference between the columns is what the tenant's own outcomes show (in the example, open tickets count about twice as much for this tenant as for the pool). `weights` is `null` while the tenant has no fit of its own.
* **`reason`** says why:
  * With its own fit: `tenant_better`, `pooled_better` or `raw_better`.
  * Before that: `too_few_outcomes`, `awaiting_fit` (the template's next fit makes one, within a day, or sooner when you ask for a fit) or `plan_required`.
  * `non_production`: the tenant is under a non-production prefix, so it reads the pool and adds nothing to it.
  * `pooled_only`: a `choice` or `score` with features, where each tenant reads the pool.
  * `pinned`: the template pins a fit for the version and epoch.
* **`tenant.current`** and **`tenant.challenger`** hold the tenant's own fit and the night's, each measured against the pool (`fallback: pooled`) on the tenant's own outcomes since. See [read the current fit and the challenger](/calibration/promotion#read-the-current-fit-and-the-challenger).

The epoch's `stage`, `held_out`, `not_fitted` and `calibrated` then describe the fit the tenant reads, measured on its own outcomes. On a tenant with its own fit, `held_out_metrics` is `null` and the tenant's own test gives no `holdout` or standard errors. `lift` is `null` on every tenant, since the template's report has the pool's lift.

Each epoch's `tenants` on the prefix path counts the tenants with outcomes in the epoch, and how many of them read their own fit, the pool or raw.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.