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

# Decisions

> The record of what your organization committed to, whether the change actually happened, and what the evidence said afterwards — over MCP, REST, or the CLI

# Decisions

A **Workstream** remembers a great deal of context: what was discussed, what was tried, what
somebody suggested. A **decision** is the narrower thing your organization actually committed
to — a course, the reason it was chosen, who authorized it, and what it changed in the outside
world. Approving a card records one. So does an agent committing to a strategy that changes
nothing outside Erdo, such as which audience a campaign targets.

The record exists to answer questions that used to have no data behind them. What did we decide
about this campaign, and why? Did the change actually go through? Did leads or cost move
afterwards, and how strong is that evidence? And the one every other question is really asking:
can this be trusted to make these calls without me?

A decision is not a log line. It is authoritative until an explicit later decision supersedes
it, which is what lets an agent picking work up weeks later continue what you agreed rather than
re-argue it — and what makes a change of course visible, because reversing a decision records a
new one naming the decision it replaces.

<Note>
  Decisions are part of the work engine and roll out with it. Until Workstreams are enabled for
  your workspace, these endpoints and tools return `permission_denied` ("workstreams are not
  enabled for this organization") — contact us to get switched on.
</Note>

## What a decision carries

* **The commitment** — `what` in one line of business English, and `why`: the argument the
  proposal was made on. When the person deciding gave their own reason for accepting, refusing or
  correcting it, that is kept separately as `decider_rationale`. The two are never merged: a
  proposal's argument read months later as the approver's reason for saying yes is a motive
  nobody stated.
* **The class** — a stable, provider-agnostic name for the kind of decision this is
  (`paid_media.ad_group.pause`, `page.publish`, `experiment.variant.stop`). It is what the
  scorecard groups on, so it survives a tool being renamed or split.
* **Applicability** — `standing` for a course that outlives the work it authorized, `one_shot`
  for an authorization covering exactly the actions it named. A page that published on Tuesday is
  not a course anybody continues; "target finance leaders on this campaign" is.
* **The authority** — who exercised the judgement (`human`, `llm_agent`,
  `deterministic_policy`, `safe_default`, `system`) and, where relevant, which person and which
  agent run.
* **The subject** — the campaign, page, or lead form the decision is about, so the record is
  searchable by the thing that changed.
* **The ask it answers** — for a decision that came from an approval, the `approval_id` of the
  card somebody answered. It is on the row and it is also a filter, so you can go from an approval
  straight to what answering it produced, whether the answer was yes or no. One approval can name
  several decisions: a batch is split into one decision per coherent intent once it is answered.
* **Actions** — one row per exact external call the decision authorized, each with its own
  subject and its own execution result. A batch that pauses four ad groups keeps four results, so
  a partial success stays visible instead of collapsing into one flag.
* **Expected effects** — what the decision said, in advance, it would move: the metric, the
  predicate that counts as success, the windows to judge it over, and any guardrails. Most
  decisions declare none, and that is the honest answer rather than a gap — a permission fix has
  no business effect anything could measure.

## The lifecycle

```text theme={null}
proposed → authorized → executing → effective → measuring → settled
proposed → rejected
authorized | executing → failed
effective | measuring → censored
```

`effective` means the change is live in the outside world. `measuring` means its declared
expectation is being watched. `settled` means the evidence came in. `censored` means something
intervened — usually a later decision replacing this one mid-window — so there is no honest
before-and-after left to compute; the decision still stands, what was lost is the ability to
score it.

An action Erdo could not confirm ends `unknown` rather than succeeded or failed. That state is
kept deliberately: the change may be live and nothing verified it, and it is resolved by reading
the provider back, never by trying again.

## How an outcome is described

Every settled outcome carries the **kind of evidence** that produced it, and the words Erdo uses
depend on it. This is not a stylistic preference — a before-and-after movement presented as proof
the change caused it is the most damaging thing this record could produce, so the vocabulary is
fixed to what the evidence can support:

| Evidence        | What it establishes                                                                                          | Met               | Not met                  |
| --------------- | ------------------------------------------------------------------------------------------------------------ | ----------------- | ------------------------ |
| `deterministic` | The specified state exists — the page is live, the campaign is paused. It says nothing about business value. | confirmed         | not confirmed            |
| `experimental`  | A controlled comparison against a concurrent arm.                                                            | worked            | did not work             |
| `observational` | A before-and-after movement with no control.                                                                 | moved as expected | did not move as expected |

An uncertain or stale result is `inconclusive` under every kind, with a reason recorded — a
result nobody can explain is a result nobody can act on.

Erdo sends the phrase itself as `outcome_label` on every read, so each surface says the same
thing about the same row rather than deriving its own wording.

## The scorecard

`decisions scorecard` reports **raw counts with their denominators**. It deliberately publishes
no eligibility verdict and no single pooled "worked rate":

* **Totals** — every decision in the window, split by status and by producer family, with the
  backfilled legacy history named separately so the numbers reconcile.
* **Execution** — how many decisions authorized an external call at all, how many actions ran,
  and how each ended, with the unconfirmed ones counted rather than absorbed into a success rate.
* **Measurement coverage** — how many decisions declared an expectation, how many effects
  exist, and where each one sits: settled, censored, or waiting on a measurement Erdo cannot yet
  read. A met rate over six settled effects out of two hundred decisions is a different claim from
  the same rate over a hundred and eighty, so the denominator travels with it.
* **Outcomes, stratified** — the settled split cut by decision class and evidence kind, and
  again by producer family and evidence kind. Never pooled: averaging a deterministic
  confirmation against an observational movement produces a number that is wrong in whichever
  vocabulary you read it in.
* **Deciders** — who exercised the judgement, how often the safe default applied because nobody
  answered, and how often a person refused something the system proposed.
* **Time to authorize** — the median and 90th percentile wait between a decision being proposed
  and being authorized.

Nothing in this readout changes your autonomy settings. Your configuration stays the ceiling; the
scorecard is evidence you read, never something that grants Erdo more authority.

## CLI

```bash theme={null}
# The whole record, newest first
erdo decisions list
erdo decisions list --json

# Narrow it — filters compose
erdo decisions list --workstream brickell-lead-strategy
erdo decisions list --class paid_media.ad_group.pause --status settled
erdo decisions list --subject-kind campaign --subject-ref 24033607833
erdo decisions list --applicability standing        # the courses currently in force
erdo decisions list --outcome not_met               # what did not do what it promised
erdo decisions list --approval <approvalId>         # what answering that card produced

# One decision in full
erdo decisions show <slug>
erdo decisions show <slug> --json

# The raw scorecard
erdo decisions scorecard
erdo decisions scorecard --workstream brickell-lead-strategy
erdo decisions scorecard --since 2026-07-01T00:00:00Z --until 2026-08-01T00:00:00Z
erdo decisions scorecard --json
```

`erdo decisions list` prints one row per decision: the slug, its status, its execution result,
what it was, and — only once something settled — how it turned out, in the words its evidence
supports.

`erdo decisions show` prints the drill-in in the order the record means something: the commitment
and its authority, then what was actually attempted, then what was expected and what the evidence
said, then what this decision replaced or was replaced by.

Decisions are referenced by **slug**, never UUID. Commands act on your active organization; pass
`--org <idOrSlug>` to pin a different one.

## MCP tools

| Tool                      | Description                                                                                                                                                                                                                                                  |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `erdo_list_decisions`     | Search the record. Filter by `workstream_slug`, `source`, `decision_class`, `subject_kind` + `subject_ref`, `status`, `applicability`, `outcome`, or `approval_id` — the ask that was answered.                                                              |
| `erdo_get_decision`       | Read one decision in full by `decision_slug`: the commitment and its rationale, who decided it and under what authority, every exact action with how it ended, every declared effect with the evidence that settled it, and supersession in both directions. |
| `erdo_decision_scorecard` | Raw aggregates with denominators, stratified by decision class and evidence kind. Optional `workstream_slug`, `source`, `decision_class`, `since`, `until`.                                                                                                  |

Identity and access ride the request context, so a caller only ever reaches their own
organization's record — and inside it, only the projects they can view. A decision filed under a
workstream inherits that workstream's project access, so a teammate who was never given a
restricted project sees none of its decisions in the search, cannot open one by slug, and does not
have its rows counted into the scorecard's totals. Decisions that belong to no workstream — a page
publish, an email send — are organization-level and stay visible to everyone.

## REST

| MCP Tool                  | REST Endpoint             | Method |
| ------------------------- | ------------------------- | ------ |
| `erdo_list_decisions`     | `/v1/decisions`           | GET    |
| `erdo_get_decision`       | `/v1/decisions/:slug`     | GET    |
| `erdo_decision_scorecard` | `/v1/decisions-scorecard` | GET    |

Base URL `https://api.erdo.ai`. Authenticate with `Authorization: Bearer <token>` and select the
org with `X-Organization-ID`.

```bash theme={null}
# Everything decided about one campaign
curl "https://api.erdo.ai/v1/decisions?subject_kind=campaign&subject_ref=24033607833" \
  -H "Authorization: Bearer YOUR_API_KEY"

# What answering one approval produced
curl "https://api.erdo.ai/v1/decisions?approval_id=<approvalId>" \
  -H "Authorization: Bearer YOUR_API_KEY"

# One decision in full
curl https://api.erdo.ai/v1/decisions/<slug> \
  -H "Authorization: Bearer YOUR_API_KEY"

# The scorecard for a period
curl "https://api.erdo.ai/v1/decisions-scorecard?since=2026-07-01T00:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

`GET /v1/decisions` pages with `limit` (default 50, max 200) and `offset`, newest first. An
unrecognised value in a closed vocabulary — a misspelled `status`, a `source` that does not
exist — is refused rather than ignored, because silently dropping the filter would return the
whole organization to a caller who asked for one slice of it. `approval_id` is refused the same
way when it is not a UUID, and it narrows within your access rather than around it: an approval
answered inside a project you cannot view matches nothing.

`GET /v1/decisions/:slug` returns the decision, its actions, its effects, and its lineage. A slug
belonging to another organization comes back `404` rather than `403`, so a slug can never be
probed for existence.

`GET /v1/decisions-scorecard` takes `since` and `until` as RFC3339 timestamps (`since` inclusive,
`until` exclusive) and echoes the window back on the response, so a readout can never be quoted
without the period it covers.
