> ## 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.

# Judge an item with what it sits under

> Show each item in a tree the items above it, from a list of their ids you keep on the item: what it reads, why the list must hold every ancestor, and what a change near the root costs.

Some questions about an item depend on what it sits under. Is this folder inside one under a legal hold? Is this team part of a department being restructured? Is this listing in a category the marketplace restricts? Is this reply part of a thread that turned hostile? Write each item's ancestors as a list of their ids, nearest first, in one attribute, such as `attributes.ancestors` set to `["cases", "legal"]`, and the judgment reads the documents the list names. That is a [named list](/guides/referenced-document#name-several-documents), one of the [relations](/concepts/relations).

```mermaid theme={"theme":{"light":"css-variables","dark":"css-variables"}}
flowchart LR
  f["folder: contracts<br/>ancestors: cases, legal"] -- "1st" --> c["cases"]
  f -- "2nd" --> l["legal"]
  f:::judged
  classDef judged stroke-width:3px
```

The folder `contracts` sits in `cases`, which sits in `legal`, so its list is `["cases", "legal"]`. Its judgment reads both directly by id, its parent first; it never reaches `legal` through `cases`.

## Start from the hierarchy starter

The `hierarchy.inherits_risk` [starter](/guides/starter-judgments#hierarchy-does-this-item-inherit-a-risk-from-what-it-sits-under) is this judgment, ready-made. Fill it with your own paths:

```json POST /v1/namespaces/acme%2Fdrive/judgments theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{
  "from_starter": "hierarchy.inherits_risk",
  "paths": {
    "kind": "attributes.kind",
    "item_kind": "folder",
    "ancestors": "attributes.ancestors",
    "name": "state.name",
    "status": "attributes.status",
    "description": "state.description"
  },
  "engine": {"name": "jev", "version": "current"},
  "freshness": {"policy": "on_change"},
  "confirm": true
}
```

* **Write the list on every item**: its parent's id, then its parent's parent's, and so on to the root, as an array of document ids. A root item has an empty list or none. Up to 254 distinct ids; an id listed twice counts once, at its first place.
* **It judges every item**, the documents whose `kind` is `folder`, and reads each one's name, its status and the first 500 characters of its description. From its list it reads the nearest 10 ancestors, in the list's order: each one's name, status and the first 300 characters of its description.
* **What renders nothing.** An id that names no document, or one whose `kind` is not `folder`, renders nothing, and the evaluation's `related_documents` lists it with `unresolved: true`. When the items above are of another kind, such as a reply under a post, send `dry_run: true`, change the relation's `match` to list both kinds (`{"attributes.kind": ["reply", "post"]}`) and create from that definition.
* **Thresholds.** `restricted` at 0.8 and `review` at 0.5: restrict an item above `restricted`, and send the band between them to a person. These are starting points; post outcomes to [measure and tune them](/guides/measure-improve-tune).

In the dashboard, the relation editor's "Add: Ancestors in a tree" fills the same relation; set the judgment's Applies to to the items in the tree.

Unless the namespace already has one, the first version also builds a reference index on `attributes.ancestors`, listed as a `reference_index` job in the create response's `job_ids`; the judgment's answers are `unavailable` until it is done. If an item already lists more than 254 ids, the job fails naming it: shorten those lists and create the version again. From then on, a write that puts more than 254 distinct ids in the attribute is refused with `invalid_request`, naming it.

The context is capped at 1,500 tokens with `max_tokens`, which keeps each judgment standard in [size](/pricing#judgments). Over the cap, the farthest ancestors are left out first, before any of the item's own fields are cut, and the evaluation records `context_truncated: true`.

## You keep the tree

The list is yours. Brussle reads what each list names, as written, and does not work it out from a parent id or check that the lists form a tree.

* **Moving an item moves its list, and every list beneath it.** Moving a folder means rewriting its own list and the list of every item under it. Each of those writes re-judges that item.
* **Nothing checks the shape.** A list that skips a level, names an item that is not above this one, or loops back is read as written. Keep the lists acyclic and complete: the judgment can only see what the list names.
* **Nearest first matters.** The judgment reads the first 10 ids. Put the parent first, so a deep item still reads the ancestors nearest it; if the root matters most to your question, raise `last_n` (up to 254) rather than reversing the list.

## A list is one hop, not many

The item reads every ancestor directly, by its id. It does not read what its parent read, so a judgment cannot pass a restriction down the tree one level at a time: that is why the list holds every ancestor, not just the parent. A list of 254 ids is 254 documents read in one step, not 254 levels.

The judgment reads the ancestors' own fields. It can also read their answers to another judgment, such as a `restricted` judgment on each folder that reads only the folder's own fields, by adding `answers.restricted.thresholds.restricted` to the relation's fields. That is one more level of [judgments reading judgments](/guides/roll-ups#three-levels), and a chain is at most three deep. The judgment can never read its own answers on the ancestors: nothing reads itself. The judgment it reads must be active, `on_change`, and apply to every item the list names. See [roll up answers from related documents](/guides/roll-ups#what-a-judgment-can-read).

## What it costs

An item's own writes re-judge it, as for any judgment. The cost to plan for is the other direction: a change to what an ancestor shows re-judges every item that lists it.

> **re-judgments a month = ancestor changes a month × items listing the ancestor inside the re-judge scope**

```mermaid theme={"theme":{"light":"css-variables","dark":"css-variables"}}
flowchart LR
  c["cases<br/>ancestors: legal"] --> l["legal"]
  k["contracts<br/>ancestors: cases, legal"] --> l
  n["nda<br/>ancestors: contracts, cases, legal"] --> l
  l -. "a change" .-> f(["re-judges all three"])
  c:::judged
  k:::judged
  n:::judged
  classDef judged stroke-width:3px
```

Each of the three folders lists `legal`, at whatever depth it sits, so one change to what `legal` shows re-judges all three.

* **A change near the root reaches the tree beneath it.** Every item listing a changed folder is re-judged, at any depth, because each lists it directly. Raising `last_n` does not change this: every id in a list counts, whatever the judgment shows. An item whose context did not change, because the changed ancestor was past its first 10, is not billed but counts toward the rolling limit.
* **Each ancestor's changes are debounced on their own**: re-judged once the ancestor has had no change for `freshness.fanout.debounce_ms`, 10 minutes by default, or at most once every `fanout.max_wait_ms`, 1 hour by default, while changes keep coming. An item whose several ancestors change at once may be judged once for each. An edit to a field the judgment does not show, or past a cut, re-judges nothing.
* **The scope.** `freshness.fanout.scope.created_within` is 30 days by default: an item created longer before the change is not re-judged, and keeps its answer reading `stale` with `stale_reason` `referenced_changed` until its own next write. In a tree the old items usually matter as much as new ones, so send `"scope": {"created_within": null}` and let the rolling limit bound the cost.

Each item's context and question come to under 2,000 tokens: a standard [judgment](/pricing#judgments), at \$0.25 per 1,000. A drive of 200,000 folders, with `created_within: null`:

| Case | Ancestor changes a month | Items per change | Re-judgments a month | Cost a month |
| - | -: | -: | -: | -: |
| **A.** 2,000 edits to folders' names, statuses or descriptions, each with 40 folders beneath on average | 2,000 | 40 | 80,000 | \$20 |
| **B.** One edit to the root's description | 1 | 199,999 | 199,999 | \$50 |

A runs well inside the default rolling limit of 300,000 re-judgments in any 30 days. B on its own spends two-thirds of it: in a month with both, the folders that fit are re-judged and the rest wait, reading `stale` with `stale_reason` `limit_reached`, until the window has room or a `PATCH` raises the limit. Keep fast-changing fields off the ancestors the judgment shows, and show a number as [bands](/guides/context-recipes#bands) if it moves often.

### What you confirm

Without `confirm: true`, the create returns its cost estimate and creates nothing. `replay` counts the items' own writes, with each item's own list, so its size classes follow your lists' lengths. It cannot count changes to ancestors, so it says `"excludes": ["fanout"]` with `lower_bound: true`. What they can add is bounded by the rolling limit, and `fanout.cost_usd_at_limit` prices it: the most ancestor changes can cost in any 30 days. Sending `confirm: true` agrees to both. See [what the replay estimate cannot count](/guides/referenced-document#what-the-replay-estimate-cannot-count).


## Related topics

- [Relations](/concepts/relations.md)
- [Starter judgments](/guides/starter-judgments.md)
- [Draw documents to label](/api-reference/outcomes-and-calibration/draw-documents-to-label.md)
- [Roll up answers from related documents](/guides/roll-ups.md)
- [Match one record to another](/guides/entity-matching.md)


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