# Outcome reporting

When **your** executor acts under a binding authorization, tell Quattrino what actually happened:

```
POST /api/v1/authorizations/{authorization_id}/outcome      (agent credential)
```

This **consumes** the authorization exactly once, commits the actual amount against the reservation, compares
every reported dimension with the authorized terms and stores the result as evidence. The authorization itself is
immutable - deviations become **findings**, never rewrites.

## Request

| field | type | notes |
|---|---|---|
| `success` | bool | **required** - did the action complete? |
| `provider` | str | e.g. `amazon`, `stripe`, `internal` |
| `provider_reference` | str | order / charge / ticket id |
| `actual_amount_minor` | int | what was actually charged / committed |
| `currency` | str | default the authorization currency |
| `merchant` | str | the counterparty actually used |
| `commitment` | enum | `ONE_TIME`, `SUBSCRIPTION`, ... actually created |
| `disclosed_fields` | [str] | data scopes actually shared (`shipping_address`, `email`, ...) |
| `delegations_performed` | [..] | delegations your executor made |
| `material_result` | str | free text (e.g. `card declined`) |
| `receipt`, `side_effects`, `protocol`, `category`, `action_type`, `attributes` | | optional evidence |
| `proof_id`, `proof_verified` | str, bool | link the outcome to the portable proof the executor verified |

Report what you know. Dimensions you do **not** report are `unverified_dimensions` - never assumed compliant.

## Response (real)

Success, matching terms:

```json
{ "status": "CONSUMED",
  "consumption": { "consumed": true, "consumed_at": "2026-09-26T05:07:15Z", "consumer": "external_executor" },
  "outcome": { "source": "external_executor", "final": true, "success": true, "provider": "amazon", "provider_reference": "114-2233",
               "actual_amount_minor": 1999, "currency": "USD", "merchant": "Amazon", "commitment": "ONE_TIME",
               "proof_id": "proof_...", "proof_verified_before_execution": true, "recorded_by": { "type": "agent", "agent_id": "agt_..." },
               "mismatch": { "matched": true, "flags": [] } },
  "compliance": { "status": "COMPLIANT", "findings": ["COMPLIANT"], "flags": [],
                  "unverified_dimensions": ["delegation", "purpose"],
                  "compared": ["amount", "counterparty", "commitment", "data", "delegation", "time", "purpose"],
                  "rule": "the authorization is immutable; every deviation is a finding; dimensions the executor did not report are UNVERIFIED, never assumed compliant" } }
```

Success, but the executor charged `$24.99` on a `$19.99` authorization (ceiling `$20.00`):

```json
{ "status": "CONSUMED",
  "compliance": { "status": "NONCOMPLIANT", "findings": ["AMOUNT_EXCEEDED"],
    "flags": [ { "code": "amount_exceeds_authorization", "authorized_minor": 1999, "effective_maximum_minor": 2000, "actual_minor": 2499, "severity": "critical" },
               { "code": "amount_exceeds_effective_authority", "effective_maximum_minor": 2000, "actual_minor": 2499, "severity": "critical" } ] } }
```

The owner is notified (`firewall_alert` "Authorization outcome mismatch"); the record stays `CONSUMED` with the findings.

Failure (`success: false`, `material_result: "card declined"`): `status: CONSUMED`, `compliance: COMPLIANT`, the reservation is released.

## Compliance findings (`family: OUTCOME_COMPLIANCE`)

`COMPLIANT`, `AMOUNT_EXCEEDED`, `AMOUNT_DRIFT`, `COUNTERPARTY_MISMATCH`, `COMMITMENT_DRIFT`, `DATA_SCOPE_DRIFT`,
`DELEGATION_DRIFT`, `TIME_VIOLATION`, `PURPOSE_OUT_OF_SCOPE`, `MATERIAL_MISMATCH`, `UNAUTHORIZED_COMMITMENT`, `UNAUTHORIZED_DELEGATION`, `UNAUTHORIZED_DISCLOSURE` - full list at `GET /api/v1/public/reason-codes?family=OUTCOME_COMPLIANCE`.

## Errors

| HTTP | `code` | meaning |
|---|---|---|
| 409 | `outcome_already_recorded` | single consumption - you already reported this authorization |
| 409 | `authorization_not_executable` | status is `REVOKED`, `EXPIRED`, `DENIED`, `APPROVAL_PENDING`... ("Outcome cannot be recorded in status REVOKED") |
| 404 | `not_found` | unknown or another agent's authorization |

No `Idempotency-Key` is needed on `/outcome`: single consumption already makes a retry safe (the retry returns 409 and
you read the stored outcome with `GET /authorizations/{id}`).

## Then explain

`GET /api/v1/authorizations/{id}/explain` -> `what_happened`, `outcome_matched_authorization`, `mismatch_flags`,
`provenance`, `evidence`, `lifecycle` and a `plain_language` paragraph that ends with `Compliance: COMPLIANT`.

SDK: `q.record_outcome(id, success=..., ...)`, `q.explain(id)`. MCP: `authorization_outcome`, `authorization_explain`.

If no outcome arrives before `expires_at`, the authorization becomes `EXPIRED`, the reservation is released and the
owner sees a "No outcome reported" alert.
