# Confidence

How sure CastHQ is of a fact about an event, as a **level** and the
**reasons** for it. Never a number: a percentage would claim a precision
nobody has. Three facts carry a level: `schedule`, `status` and `location`.

Levels, strongest first:

| Level | Meaning |
|---|---|
| `confirmed` | The producer (the party the event belongs to) or CastHQ stated it, and for a date, to the day or finer. Not stale |
| `likely` | The producer at a coarser precision (a month, a quarter); or two or more independent source domains agree; or a registered source on the producer's own verified domain backs it; or a confirmed date gone stale |
| `uncertain` | One source, community reports only, no date (`tba`), or nobody has said anything |
| `disputed` | An open, sourced disagreement that CastHQ has not ruled on (see [Reconciliation](/reconciliation#disputes)) |

For conditions, levels order low to high as `disputed` < `uncertain` <
`likely` < `confirmed`: a disputed date is less to be relied on than one
nobody has confirmed yet.

## Reasons

Stable codes. A code with a value carries it after a colon. Branch on the
code, show the level.

| Reason | Meaning |
|---|---|
| `producer_asserted` | The value shown is the producer's claim |
| `producer_slip_rate:<rate>` | Beside `producer_asserted` on a date: the share of the producer's settled dates in the event's topic that slipped (moved later, undated, postponed), once there are 5. On an occurrence of a series (and on the series) with 5 past occurrences, the series' own rate instead: the share of them moved or cancelled against its rule. Informs; moves no level. See `GET /v1/topics/{id}/reliability` |
| `series_rule` | The date is one occurrence of a repeating series, derived from the series' rule and judged at the rule's standing; it never goes stale (the series' slip rate tempers it instead). A date set for that occurrence itself is judged on its own and carries none |
| `admin_ruled` | The value shown is CastHQ's ruling |
| `sources_agree:<n>` | `n` (2 or more) independent source domains assert the value shown |
| `single_source` | The value rests on one source domain, or none |
| `community_only` | Only CastHQ members reported it, with no source |
| `verified_domain_source` | A registered source on the producer's verified domain backs it |
| `precision:<p>` | The schedule's precision (`day`, `month`, `quarter`, `tba`, …) |
| `contested_by:<origin>` | A party of that origin disputes the value shown |
| `stale:<YYYY-MM-DD>` | The newest corroboration is from that day, older than the event's nearness allows |
| `unclaimed` | Nobody asserted this fact |
| `rules_changed` | On a `confidence` change only: CastHQ's rules moved the level, not the record |
| `dependency_at_risk:<event>` | Reserved for dependencies between events; not emitted yet |
| `variants:<n>` | On a variant parent's date (an event with per-region, per-platform or per-shard variants): its schedule is derived from its variants, and its level is the lowest of its `n` dated, non-cancelled variants' levels, so the parent's date is `confirmed` only when every variant's is |

New codes may appear within a version. Treat an unknown code as
information, not an error.

## Independence

Sources are counted by **domain**, not by account. `news.example.com` and
`example.com` are one source; ten agents citing one blog post are one
source. A claim with no public evidence link counts toward no domain. This
is what stops anyone from making a date look settled by repeating it.

The same count is in every change's snapshot as `fact_sources` (per fact,
how many independent sources agree with the shown value), so a condition
can wait for "three sources agree":
`{"fact": "schedule", "sources": {"becomes_at_least": 3}}` (see
[Conditions](/conditions)). It is a count, not a score: the levels above
are what to rely on.

## Staleness

A confirmed date for an upcoming event goes stale when its newest
corroboration is older than a horizon that shrinks as the event nears, and
drops to `likely` with `stale:<day>`:

| Event starts in | Horizon |
|---|---|
| more than 90 days | 180 days |
| 31 to 90 days | 90 days |
| 8 to 30 days | 30 days |
| 7 days or less | 14 days |

A date that has already started is history, not a forecast, and does not go
stale.

## Changes in confidence are changes

When a level moves, CastHQ records a `confidence` change (type
`co.casthq.event.confidence.<level after>`) with `data.confidence` =
`{fact, before, after, reasons}`, in the same transaction as the claim that
moved it. A claim that changes only how many sources agree (a new site
backing the value already shown, level unchanged) records one too, with the
same level either side. Every change's `before` / `after` snapshot carries the level of
each fact as it was then, so a condition replayed over history reads the
confidence at that moment, not today's.

The rules are versioned. When CastHQ changes them, every stored level is
recomputed, and each one that moves is a `confidence` change with
`rules_changed` among its reasons.

## Where to read it

- `confidence` on the status answer: `GET /v1/events/{id}/status`, MCP `event_status`
- `facts` in every change's `before` / `after`
- The `confidence` front matter of an event's Markdown (`/{topic}/{event}.md`)
