# Glossary

> The words the panel and these docs use, in one place.

Source: https://www.patterna.nl/docs/glossary

**Abandonment.** Your client tells Patterna it gave up on a slate or hid the block (`POST /recommendations/{request_id}/abandon`, answered `200`). The slate keeps its arm and counts in the fallback rate, flagged `client_abandoned` with a reason (`timeout`, `server_error`, `network_error`, `bad_response` or `client_fallback`).

**Arm.** The group a unit is assigned to while a holdout runs on a surface: `treatment` or `control`. Every other slate (no running experiment, `shadow`, `testers`) has arm `none` and never enters the ledger. Arms are sticky: the same user stays in the same arm.

**Assignment unit.** An optional top-level field on `non_profiled` requests, 64 hex characters: an HMAC-SHA256 your backend computes from its own user id under a key it holds, so a person keeps one arm across sessions. Used only for the arm and `unit_hash`; never stored raw. See [Identity across connectors](https://www.patterna.nl/docs/identity-across-connectors).

**baseline_rate.** The metric's rate today, used with `relative_change` to size a holdout (`readable_sample`). Take it from your own analytics for the block you replace; for a new block, read the control rate off the surface after a week of traffic. Left empty, the ledger uses the observed control rate and a 20% change.

**blocks_shown.** The blocks of a page a slate was seen in, recorded on the impression from `seen` interactions that carry `block`. The ledger writes a row per block (`by=block`) and the surface metrics filter on it.

**Clustered interval.** A 95% interval that treats all slates of one user (or session) as one unit, because they are not independent. The ledger computes it with the delta method. See [Proof and the ledger](https://www.patterna.nl/docs/proof-and-the-ledger).

**Cohort.** A consent mode. Recommendations use the user's declared goals only, no behaviour. The learning jobs leave cohort users' events out.

**Consent mode.** How much Patterna may know about a user: `personalized`, `cohort` or `non_profiled`. See [Consent modes](https://www.patterna.nl/docs/consent-modes).

**Control.** The holdout arm that gets the surface's editorial list (newest, curated ids or 7-day popular), logged with policy `editorial`, propensity 1 and a reason. It is the comparison, not a fallback. On an anchored surface control serves your own list for the page from `context.control_item_ids` when you send one, else the surface's `fallback.by_anchor` list for the anchor; the answer's `control_source` says which.

**device_resort.** A surface setting: the app may re-order the slate on the device. Every interaction must then carry `displayed_position`; the engine keeps the served position for the propensities.

**Diversity.** `filters.diversity` (0 to 1) in the flow config: a penalty on items similar to the ones already picked, applied inside the sampler so propensities stay exact. The only diversity setting.

**Effective sample size.** How many logged impressions really inform an off-policy estimate. It drops when the new flow ranks very differently from what was logged.

**event_id.** The idempotency key of an event, unique per tenant. Sending it twice stores it once.

**Example mode.** The panel's view of the synthetic example data from the twin, flagged `synthetic`, so an empty workspace shows what every screen looks like. Nothing in it enters the ledger.

**Exploration share.** The share of requests in the treatment arm or outside any holdout (arm `none`) on which the sampler explores with Plackett-Luce instead of returning the deterministic top-k. Control is never explored. From the flow's `exploration.share`, else the surface's `exploration_share` (default 0.2); at most 0.5.

**Fallback.** The safety net: when a request that should have been ranked times out or hits storage trouble, or the surface has no active flow, Patterna answers with the editorial list and `fallback: true`, logged in the assigned arm. The fallback rate is fallback slates (safety-net fallbacks plus slates the client abandoned) over non-shadow slates served; on a surface's page `shown: false` slates are left out of both counts. Control slates never count. Your backend also keeps its own list for when Patterna does not answer within 150 ms. See [Timeouts and what counts in the ledger](https://www.patterna.nl/docs/timeouts-and-the-ledger).

**Flow.** The recipe of a surface: generators, filters (including `filters.diversity`), ranker, exploration and reason overrides. See [Surfaces and flows](https://www.patterna.nl/docs/surfaces-and-flows) and the [Flow config reference](https://www.patterna.nl/docs/reference-flow-config).

**Flow version.** A saved, numbered flow config. Saving creates a new version; activating one is audited; the previous version stays available for rollback.

**Generator.** A scorer of candidates, twelve of them: `trending`, `curated`, `item_to_item`, `session_items`, `vector_retrieval` (also a candidate source: it fetches the nearest items by content), `content_affinity`, `persona_bayes`, `user_bayes`, `user_to_user`, `surface_specific`, and the silent `time_fit` and `format_fit`, which move scores but never name a reason. Each score is normalised and weighted; the largest contribution wins the slot and sets its reason key.

**Holdout.** An experiment where part of the traffic (the control arm) gets the editorial list. The difference between arms is the proof. Pilot default: 50/50, sticky per user.

**Intention to treat.** Every served slate counts in its arm, seen or not, including slates the client gave up on. See [Timeouts and what counts in the ledger](https://www.patterna.nl/docs/timeouts-and-the-ledger).

**Impression.** One slate served to one user or session, logged with its arm, every position and its propensity. Impressions are not the unit of the interval; users (or sessions) are.

**Ledger.** The table per surface with the holdout difference, its interval, slates and units per arm, the SRM p-value and a readable flag. Intention to treat. Not yet recomputable from the export alone (the proof export lacks the unit, `measured`, `not_shown` and the experiment window; see [Status](https://www.patterna.nl/docs/status)). Synthetic rows are excluded.

**Measured.** `context.measured: false` marks a slate for a user who did not allow usage analytics. It is served as usual but left out of the ledger, power and learning in both arms.

**Minimum detectable effect.** The smallest relative change a holdout can show with its sample at 5% two-sided and 80% power. `relative_change` is the change you choose to detect; the readable sample follows from it and the baseline.

**Not shown.** A slate shorter than the surface's `min_slots`, answered with `shown: false`. It comes back with no items, counts in its arm as served with zero success, and cannot be abandoned (`409 not_shown`).

**non_profiled.** A consent mode. No user id is stored or sent; only a rotating session id and context. Patterna still learns one global, context-only policy, and the holdout still covers these sessions.

**Persona.** A named cluster of users built by the jobs. `persona_bayes` ranks per persona; users without one use the `cold` persona.

**Personalized.** A consent mode. Patterna keeps a random per-tenant user id and learns from that user's behaviour.

**Plackett-Luce.** The sampling model used for exploration. It draws items one position at a time, so the probability of every item in every position is known exactly. See [Exploration and propensities](https://www.patterna.nl/docs/exploration-and-propensities).

**Policy version.** The version of the model artifact that ranked a slate. Logged on every impression and returned in the slate.

**Pre-register.** Choosing the surface, the primary metric, the baseline and the change to detect when the holdout starts, before any result is seen. The ledger reads only that metric, so a row cannot be picked after the fact.

**Propensity.** The probability that an item was shown in a given position. Logged with every impression; needed for off-policy estimates such as SNIPS.

**Quota.** A plan's monthly number of serve requests (`request_quota_monthly`). Every `POST /recommendations` counts. A `quota_warning` notification at 90%, `429 quota_exceeded` past it until the 1st of the next month (UTC); show your own list until then.

**Readable sample.** The number of randomised units per arm an experiment needs, given the baseline and the change to detect, at 5% two-sided and 80% power. A ledger row is `readable` when each arm reaches it.

**Reason key.** The key a slot carries, set by the winning generator, for example `similar_to_read`. Flow overrides are keyed by it. The app shows the sentence in the user's locale. See [Reason keys](https://www.patterna.nl/docs/reference-reason-keys).

**Request id.** The id of one API call, in the `X-Request-Id` header and in error bodies. For a recommendation it is also the slate's `request_id`, which you echo back in `/interactions`.

**RLS.** Row-level security in Postgres. Every connection sets the tenant, so one tenant can never read another's rows.

**Round.** The internal name of an engine release in the changelog (round 4, round 5). These pages use the engine version instead: engine 0.3.1 is what `/health` reports and the contract's version.

**Scope.** What a key may do: `serve`, `ingest` or `admin`.

**SERVE_BUDGET.** The engine's own time budget for `POST /recommendations`, 120 ms by default and below the SDKs' 150 ms. Past it the engine answers the editorial list with `fallback: true`. A shorter client deadline (`X-Deadline-Ms`) wins.

**Shadow.** Two uses. As a surface status, the first one: Patterna ranks and logs every slate with arm `none`, your backend calls it as usual and discards the answer, and your app shows its own list. As a request flag, `"shadow": true` on `POST /recommendations`: rank and log this one request as not shown (arm `none`), whatever the surface's status; the panel preview uses it. Neither enters the ledger or the fallback rate.

**Signed event.** Every event sent with an ingest or admin key counts as signed. A `signature` (lowercase hex HMAC-SHA256 over the canonical event) is optional; when present it is verified and a wrong one rejects the event. Secrets are `pss_` strings and the HMAC key is the secret string itself, as the SDKs do. A secret issued before engine 0.2 has no `pss_` prefix: rotate it once.

**Slate.** The ordered list of items for one request, each with a position (from 0), reason and propensity.

**SNIPS.** Self-normalised inverse propensity scoring. It estimates from logged impressions how a different flow would have done, without running it. Used by simulate and the replay report.

**SRM.** Sample ratio mismatch. The arms are not the size they should be. A ledger row with an SRM p-value below 0.001 is flagged and should not be read.

**Surface.** One placement in your product, such as `home_articles` or `more_to_read`. It has a status, slots, an editorial list (`fallback`) and an active flow version.

**Synthetic.** Rows generated by the twin, flagged `synthetic`. They power the "example data" view and never enter the ledger.

**Tenant.** One customer workspace. Every row, key and setting belongs to exactly one tenant.

**Tenant seed.** The script that sets up a new workspace: the tenant row, its first admin key and, when agreed with you, its surfaces and settings, so you start from a filled panel. Locally `engine seed` does the same for development. A seeded surface is an ordinary surface: change it in the panel or with `patterna surface apply`.

**Testers.** The second surface status. Ids on the surface's testers list get the ranked slate; everyone else gets the editorial list, all with arm `none`. The `X-Patterna-Tester: 1` header lets your own roster decide.

**Treatment.** The arm that gets Patterna's ranked slate.

**Truth scale.** A setting of the twin: 1.0, 0.5 or 0.25, how much persona structure the simulated audience has. Simulate reports the lift at all three, so you see how much the result depends on the twin's assumptions.

**Twin.** A simulator of the tenant's users and catalog. It produces the synthetic example data and the `twin_curve` in simulate. It is not proof. See [The twin](https://www.patterna.nl/docs/the-twin).
