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

# Grade

> Score a record out of 100 from a rubric you write, with the reasoning attached.

## Overview

A Grade scores a record from **0 to 100** using a rubric you write: a list of
criteria, each worth some weight, each reading something the workspace already
knows. The score lands in a band you name, and every grade carries the
**breakdown** that produced it, so "why is this a B?" is one click rather than a
guess.

It is one property type behind four different jobs. Pick it from **Complex** in
the property type list.

<CardGroup cols={2}>
  <Card title="Lead fit" icon="user-check">
    How promising a new lead is. `A` / `B` / `C` / `D`.
  </Card>

  <Card title="Deal confidence" icon="handshake">
    How likely an open deal is to close. `Committed` down to `Unlikely`.
  </Card>

  <Card title="Customer health" icon="heart-pulse">
    Whether a live account is in good shape. `Healthy` down to `At risk`.
  </Card>

  <Card title="Churn risk" icon="triangle-exclamation">
    How likely a customer is to leave. A **high** score is bad news.
  </Card>
</CardGroup>

## Setting one up

<Steps>
  <Step title="Add the property and pick a preset">
    Create a Grade property on the object you want to score (Contacts, Deals,
    Accounts), then choose **Start from a preset**. A preset fills in the bands
    and sets which way the score reads. It deliberately does **not** write any
    criteria: a rubric depends on your own properties, so anything it invented
    would point at fields you may not have.
  </Step>

  <Step title="Check which way it reads">
    **Reads as** decides whether a rising score is good news. Leave it on
    *A higher score is better* for fit, confidence and health. Set it to
    *A higher score is worse* for churn risk, so a climbing score shows a red
    arrow rather than a green one.
  </Step>

  <Step title="Write the criteria">
    Each criterion has a label, a weight, and one thing it reads. It is all or
    nothing. The criterion either earns its full weight or earns zero. See
    [what a criterion can read](#what-a-criterion-can-read) below.
  </Step>

  <Step title="Choose when it recomputes">
    **When the record changes, and nightly** is the default and is almost always
    right. See [when it recomputes](#when-it-recomputes).
  </Step>
</Steps>

## What a criterion can read

| Reads        | What it asks                                            | Example                                   |
| ------------ | ------------------------------------------------------- | ----------------------------------------- |
| **A field**  | Does a property on this record pass a test?             | Stage is any of `Demo booked`, `Proposal` |
| **Recency**  | Has there been activity in the last N days?             | A conversation in the last 14 days        |
| **A count**  | Have there been at least N in a window?                 | 3 or more calls this quarter              |
| **A signal** | Is a [signal](/ai/recommendations) open on this record? | `account.went_quiet`                      |

Field tests cover *is any of*, *is not any of*, *is empty*, *is not empty*,
*at least*, *at most* and *contains*.

<Note>
  **A field criterion can read a computed property**, a
  [Usage](/data/properties/complex/usage) property, a
  [rollup](/data/properties/complex/rollup) or a
  [formula](/data/properties/complex/formula), the same way it reads one somebody
  typed in. That is how you score on product usage: point *at least* at
  `API calls (30d)` and the rubric does the rest.

  A Usage property is aggregated **live** each time the rubric runs, so the score
  is exact at the moment it was calculated rather than reading a stored figure. If
  the property is misconfigured, its line shows the reason and is left **out of
  the score** entirely, rather than quietly counting as a criterion the record
  failed.
</Note>

<Note>
  There is no "ask AI" criterion, on purpose. An AI-written score is one nobody
  can argue with. Instead, have a [property agent](/ai/property-agents/overview) fill a
  normal property, then read that property with a field criterion. The AI's
  contribution then earns its points as one visible line of the breakdown that
  you can see, weight, and remove.
</Note>

### How the score is worked out

Add up the weight every criterion earned, then rescale against the total of all
the **positive** weights. So a rubric of four criteria worth 30, 30, 20 and 20
that earns the first two scores `60`.

Weights can be **negative**, a penalty. A penalty subtracts from what the
positive criteria earned and is left out of the rescaling, so adding one cannot
inflate everything else.

<Tip>
  Rescaling is why you can add a fifth criterion to a four-criterion rubric
  without every existing record's score dropping. Scores only move when something
  about those records moves.
</Tip>

## Bands

A band is a **label and a floor**. Scores take the highest band they clear, and
the lowest band catches everything underneath the one above it, so there is no
gap a score can fall into and no overlap where two bands both match.

Each band also carries a **colour**, which is how an inverted grade works: churn
risk puts green on `Low` and red on `High`, the opposite of every other preset.

## Worked examples

<AccordionGroup>
  <Accordion title="Lead fit, on Contacts">
    | Criterion                      | Weight | Reads                                |
    | ------------------------------ | ------ | ------------------------------------ |
    | Works at a target-size company | 30     | Field: `Employees` at least `50`     |
    | Job title is a decision maker  | 25     | Field: `Title` contains `Head of`    |
    | Has a work email               | 15     | Field: `Email` is not empty          |
    | Replied in the last 30 days    | 30     | Recency: conversation within 30 days |

    A lead with a work email at a 200-person company who has not replied scores
    `45`, a `C`. The breakdown says exactly which two lines it missed.
  </Accordion>

  <Accordion title="Deal confidence, on Deals">
    | Criterion                        | Weight | Reads                                              |
    | -------------------------------- | ------ | -------------------------------------------------- |
    | Past the demo                    | 30     | Field: `Stage` is any of `Proposal`, `Negotiation` |
    | Champion identified              | 20     | Field: `Champion` is not empty                     |
    | Two or more calls this quarter   | 25     | Count: 2+ calls in 90 days                         |
    | Talked to us in the last 14 days | 25     | Recency: conversation within 14 days               |
    | No open blocker                  | −20    | Signal: an open blocker signal (penalty)           |

    Set **Recompute** to *When the record changes, and nightly*: the two
    time-based criteria go stale on their own, and a deal nobody has touched is
    exactly the one you want to hear about.
  </Accordion>

  <Accordion title="Customer health, on Accounts">
    | Criterion                           | Weight | Reads                                       |
    | ----------------------------------- | ------ | ------------------------------------------- |
    | On a paid plan                      | 30     | Field: `Plan` is not any of `Trial`, `Free` |
    | Spoke to us this month              | 25     | Recency: conversation within 30 days        |
    | Three or more sessions this quarter | 25     | Count: 3+ conversations in 90 days          |
    | Named owner                         | 20     | Field: `Owner` is not empty                 |
    | Open "went quiet" signal            | −25    | Signal: `account.went_quiet` (penalty)      |
  </Accordion>

  <Accordion title="Onboarding health, on Accounts">
    Driven by product usage rather than by who has spoken to whom, so a quiet
    customer who is using the thing every day reads as healthy.

    | Criterion                     | Weight | Reads                                      |
    | ----------------------------- | ------ | ------------------------------------------ |
    | Activated: sent a first event | 30     | Field: `API calls (all time)` at least `1` |
    | Using it week to week         | 30     | Field: `API calls (30d)` at least `20`     |
    | More than one seat in use     | 20     | Field: `Seats used` at least `2`           |
    | Reached out for help          | 20     | Recency: conversation within 30 days       |

    An account that has activated and uses it weekly, on one seat and with no
    contact, scores `60`: **Steady**. Sort the view by the score and work up
    from the bottom.
  </Accordion>

  <Accordion title="Churn risk, on Accounts">
    The same facts as health, pointed the other way. Set **Reads as** to
    *A higher score is worse* and write the criteria so that **firing means bad
    news**.

    | Criterion                | Weight | Reads                                                 |
    | ------------------------ | ------ | ----------------------------------------------------- |
    | No reply in 30 days      | 30     | Field: `Last contacted` is empty, or recency inverted |
    | Still on a trial plan    | 25     | Field: `Plan` is any of `Trial`                       |
    | No named owner           | 20     | Field: `Owner` is empty                               |
    | Open "went quiet" signal | 25     | Signal: `account.went_quiet`                          |

    An account hitting the first and the last scores `55`: `Elevated`, in
    amber, with a **red** arrow if it climbed to get there.
  </Accordion>
</AccordionGroup>

## When it recomputes

| Setting                              | When the rubric runs                                                          |
| ------------------------------------ | ----------------------------------------------------------------------------- |
| When the record changes, and nightly | A property the rubric reads is written, **and** a nightly sweep. The default. |
| Only when the record changes         | A property the rubric reads is written.                                       |
| Only when someone asks               | Nothing automatic: the ↻ in the grade's panel.                                |

<Warning>
  Anything reading **recency**, a **count** or a **signal** needs the nightly run.
  Those criteria only become true with the passage of time, and a quiet account is
  precisely the one nobody is editing, so with *Only when the record changes*, a
  health score can never slip on its own.
</Warning>

## What it stores

The score, the band, the breakdown that produced it, and a short history of
recent scores that drives the trend arrow. Sorting, filtering and a table's
`average` / `min` / `max` footer all see the **score** as a plain number, so a
grade behaves like any other numeric column.

## Setting one by hand

Open the grade's panel and type a score. That marks the value **manual**: it
replaces the computed one and drops the breakdown, because the rubric's
explanation no longer describes the number on screen. The trend history is kept,
so the arrow survives an override. **Clear** returns the record to the rubric.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The cell is empty on every record">
    A grade with no criteria is never scored, deliberately: a rubric with
    nothing in it would score every record **0**, and 0 is not "ungraded", it is
    the worst lead in the workspace on a number your team sorts by. Add at least
    one criterion. An empty cell also means a record the rubric has simply not
    run over yet, which the next nightly sweep or edit fixes.
  </Accordion>

  <Accordion title="The score never changes">
    Check **When it recomputes**. On *Only when the record changes*, nothing
    reading recency, a count or a signal can ever move the score, because those
    criteria only become true with the passage of time. Switch the property to
    *When the record changes, and nightly*, or press the ↻ in the grade's panel
    to run it now.
  </Accordion>

  <Accordion title="The arrow is green when the score got worse">
    That grade reads the wrong way round. Open the property and set **Reads as**
    to *A higher score is worse* for anything measuring risk. It changes nothing
    about the score or the rubric, only whether a rising number is shown as good
    news, and a preset sets it for you.
  </Accordion>

  <Accordion title="A criterion fires but the line is red">
    On a grade that reads *A higher score is worse*, an earned line is bad news
    by definition: "No reply in 30 days, +30" means the criterion worked **and**
    the account got worse. The colour describes the account, not the criterion.
  </Accordion>

  <Accordion title="A band never appears">
    Bands are matched by the **highest floor a score clears**, so a band whose
    floor sits above every score in practice is unreachable, and two bands
    sharing a floor make the lower one dead. A band missing a label or a floor is
    dropped entirely and will not show in the editor either.
  </Accordion>

  <Accordion title="A criterion I wrote does not match">
    A criterion written against a select or a user field matches either the
    option's label or the stored value, so "Qualified" and the option itself both
    work. If a field is genuinely empty on the record, the criterion earns
    nothing and the line shows `0 of <weight>` rather than being hidden.
  </Accordion>

  <Accordion title="The breakdown does not match the criteria I can see">
    The explanation is **snapshotted with the score**, not recomputed when you
    open it. If you have edited the rubric since, the panel still explains the
    score that was produced by the old one. Press ↻ to score the record against
    the rubric as it stands now.
  </Accordion>
</AccordionGroup>

## See also

* [Property agents](/ai/property-agents/overview): have AI fill a property a criterion reads.
* [Recommendations](/ai/recommendations): the open recommendations a signal criterion can read.
* [Rollup](/data/properties/complex/rollup): aggregate across related records, useful as an input to a grade.
* [Formula](/data/properties/complex/formula): compute a value from other fields on the same record.


## Related topics

- [Usage tracking](/bi/reporting/usage.md)
- [Usage](/data/properties/complex/usage.md)
- [Overview](/data/properties/complex/overview.md)
- [Coaching Scorecards](/comms/coaching/scorecards.md)
