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

# Overview

> How Odigos evaluates sampling rules: categories, order between Noisy, Highly Relevant, and Cost Reduction, conflicts inside a category, and head vs. tail sampling.

This page describes how **sampling rules** are evaluated in Odigos: the three **rule categories** (Noisy Operation, Highly Relevant, Cost Reduction), the **order between categories**, and how **conflicts inside a category** resolve. Each category has its own page; this overview focuses on how the categories interact.

## Rule categories

<CardGroup cols={3}>
  <Card title="Noisy Operation" icon="filter" href="./noisy-operation">
    Traffic with little or no value (for example Kubernetes health probes). Decided early at the **root span** with **head sampling**.
  </Card>

  <Card title="Highly Relevant" icon="star" href="./highly-relevant">
    **Important** traffic aligned with **RED**-style signals (errors, duration). Each rule's **Keep Percentage** controls how much is retained.
  </Card>

  <Card title="Cost Reduction" icon="chart-line" href="./cost-reduction">
    Caps applied to remaining traffic to control volume and cost (for example a percentage across the cluster or a specific route).
  </Card>
</CardGroup>

<Note>
  See [Head vs. tail sampling](../head-and-tail-sampling) for how head and tail sampling differ in Odigos (root-span decisions versus aggregation at the gateway).
</Note>

If you only define **Highly Relevant** rules and **no Cost Reduction** rules, unimportant traffic is not aggressively reduced by those rules alone—policy may still require full-trace context to evaluate importance, which increases gateway work without cutting volume. Use **Highly Relevant** and **Cost Reduction** together when you need both signal and volume control.

## Order of operations between categories

Categories are **not** all evaluated for every trace in parallel. Odigos applies them in this fixed **sequence**:

<div className="not-prose my-8 mx-auto w-full max-w-5xl">
  <div className="md:flex md:justify-start">
    <div className="w-full md:w-[46%]">
      <Card title="Noisy Operation" icon="filter">
        <div className="text-sm leading-snug text-zinc-700 dark:text-zinc-300">
          If the trace <strong>matches</strong> a Noisy rule, it is <strong>dropped or sampled down</strong> as configured. The trace exits the pipeline at this stage; <strong>Highly Relevant</strong> and <strong>Cost Reduction</strong> are <strong>not</strong> evaluated for that trace.
        </div>
      </Card>
    </div>
  </div>

  <div className="flex justify-center py-0.5 text-sm leading-none text-zinc-500 dark:text-zinc-400 md:hidden" aria-hidden="true">↓</div>

  <div className="hidden md:block md:h-1" aria-hidden="true" />

  <div className="relative md:flex md:justify-center">
    {/* Connector 1 overlay: vertical line drops at 25% from Noisy's left (= 11.5% of container).
              Line top sits 0.25rem below Noisy (matches spacer); arrow tip ends 0.25rem before Highly's left.
              L's right edge = (Highly left 27%) − arrow width (≈1.125rem) − gap (0.25rem) = 27% − 1.375rem. */}

    <div className="absolute hidden md:block" aria-hidden="true" style={{ top: 0, bottom: '50%', left: '11.5%', right: 'calc(73% + 1.375rem)' }}>
      <div className="absolute inset-0 border-l-4 border-b-4 border-zinc-400 dark:border-zinc-500" />

      <span className="absolute text-lg leading-none text-zinc-500 dark:text-zinc-400" style={{ left: '100%', bottom: '2px', transform: 'translate(0, 50%)', zIndex: 10 }}>▶</span>
    </div>

    <div className="w-full md:w-[46%]">
      <Card title="Highly Relevant" icon="star">
        <div className="text-sm leading-snug text-zinc-700 dark:text-zinc-300">
          Only traces that did <strong>not</strong> match any Noisy rule reach this stage. Rules here classify <strong>important</strong> traffic (for example errors and duration); <strong>important</strong> matches <strong>can still be sampled</strong> per each rule's <strong>Keep Percentage</strong>. Traces <strong>continue</strong> to <strong>Cost Reduction</strong> after this stage.
        </div>
      </Card>
    </div>
  </div>

  <div className="flex justify-center py-0.5 text-sm leading-none text-zinc-500 dark:text-zinc-400 md:hidden" aria-hidden="true">↓</div>

  <div className="hidden md:block md:h-1" aria-hidden="true" />

  <div className="relative md:flex md:justify-end">
    {/* Connector 2 overlay: vertical line drops at 25% from Highly's left (= 38.5% of container).
              Line top sits 0.25rem below Highly Relevant (matches spacer); arrow tip ends 0.25rem before Cost's left.
              L's right edge = (Cost left 54%) − arrow width (≈1.125rem) − gap (0.25rem) = 54% − 1.375rem. */}

    <div className="absolute hidden md:block" aria-hidden="true" style={{ top: 0, bottom: '50%', left: '38.5%', right: 'calc(46% + 1.375rem)' }}>
      <div className="absolute inset-0 border-l-4 border-b-4 border-zinc-400 dark:border-zinc-500" />

      <span className="absolute text-lg leading-none text-zinc-500 dark:text-zinc-400" style={{ left: '100%', bottom: '2px', transform: 'translate(0, 50%)', zIndex: 10 }}>▶</span>
    </div>

    <div className="w-full md:w-[46%]">
      <Card title="Cost Reduction" icon="chart-line">
        <div className="text-sm leading-snug text-zinc-700 dark:text-zinc-300">
          For traces that <strong>match</strong> rules in this <strong>category</strong> after the earlier stages, this stage applies caps to control volume and cost.
        </div>
      </Card>
    </div>
  </div>
</div>

The pipeline runs the categories in this order. At each stage, every rule in that category is considered; how multiple matches resolve is covered in [Rule evaluation](#rule-evaluation).

## Rule evaluation

### Evaluation inside a category

Within a single category, rule order does not matter. When multiple rules match the same trace, the engine combines them so all of them are satisfied at once.

For Highly Relevant, percentages are floors — the highest keep percentage wins, so any retention guarantee is honored. For Noisy Operation and Cost Reduction, percentages are caps — the lowest keep percentage wins, so the strictest cap is honored. This makes it safe to add rules without fear of one silently overriding another.

### Evaluation between Highly Relevant and Cost Reduction categories

When a trace matches rules in **both** the **Highly Relevant** and **Cost Reduction** categories, the **Highly Relevant** keep percentage **always wins** — regardless of whether it is higher or lower than the **Cost Reduction** cap.

<CardGroup cols={2}>
  <Card title="Highly Relevant rate higher than Cost Reduction" icon="arrow-up">
    **Trace:** `POST /api/orders` that returned a `500` error.

    **Matching rules:**

    * **Highly Relevant** — keep **100%** of error traces.
    * **Cost Reduction** — keep at most **10%** of `/api/orders` traffic.

    **Outcome:** the trace is **kept at 100%**. Highly Relevant overrides the Cost Reduction cap.
  </Card>

  <Card title="Highly Relevant rate lower than Cost Reduction" icon="arrow-down">
    **Trace:** `GET /api/products` that took **750 ms**.

    **Matching rules:**

    * **Highly Relevant** — keep **25%** of traces longer than **500 ms**.
    * **Cost Reduction** — keep at most **50%** of `/api/products` traffic.

    **Outcome:** the trace is **kept at 25%**. Highly Relevant still wins, even though its keep rate is lower than the Cost Reduction cap.
  </Card>
</CardGroup>

## Why full traces still matter

For traces that are evaluated on the **tail** path, the evaluator needs the assembled trace (within the aggregation window) so it can apply **Highly Relevant** conditions that depend on any span. That is why tail sampling and aggregation are part of the pipeline for those policies, even when the category order is Noisy → Highly Relevant → Cost Reduction.
