Skip to main content

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

What a decision carries

  • The commitmentwhat 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.
  • Applicabilitystanding 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

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: 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

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

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

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