# Treatment Management API

## Domain Meaning

A Treatment is one bounded intervention lifecycle for one or more SQL Catalog Items. A Finding does
not create a Treatment automatically. Findings create or update the long-lived Catalog dossier; a
Treatment starts only after a user or automation decides to intervene.

Every Treatment must state:

- `objective`: what operational impact this intervention intends to change.
- `success_criteria`: what evidence will make the result acceptable.
- one or more `catalog_item_ids`: the SQL dossiers in scope.

Treatment identifiers use `trt_<uuid>` internally and `TRT-0001` style numbers in the UI.

## Lifecycle

States:

| State | Meaning |
| --- | --- |
| `active` | Work is still in progress. |
| `completed` | Work ended with a non-cancellation Outcome. |
| `cancelled` | Work was stopped and documented as cancelled. |

Stages:

```text
assessment -> planning -> alignment -> execution -> observation -> completed
```

Supported backward or shortened transitions are:

- `planning -> assessment`
- `planning -> execution`
- `alignment -> planning`
- `alignment -> execution`
- `execution -> planning`
- `observation -> execution`

Entering `observation` and `completed` requires their dedicated domain actions. Generic `PATCH`
cannot change `state`, `stage`, `outcome`, or completion fields.

## Start A Treatment

`POST /api/v1/treatments`

All endpoints require `Authorization: Bearer <access-token>`. Timeline and audit actors are derived
from the authenticated application user; clients do not submit `actor` or `created_by`.

| Field | Type | Required | Meaning |
| --- | --- | --- | --- |
| `catalog_item_ids` | string[] | yes | One to 50 Catalog Item IDs. |
| `finding_ids` | string[] | no | Evidence Findings to link. If omitted, all active Findings for the selected Catalog Items are linked. |
| `title` | string | no | Human-readable title. A digest-based title is generated if omitted. |
| `objective` | string | yes | Intervention objective, up to 2,000 characters. |
| `success_criteria` | string | yes | Measurable completion criteria, up to 4,000 characters. |
| `owner` | string | no | Accountable owner. |
| `assignee` | string | no | Current executor. |
| `priority` | string | no | Defaults to `normal`. |
| `severity` | string | no | Defaults to the first Catalog Item severity. |
| `labels` | string[] | no | Product-owned labels. |

```json
{
  "catalog_item_ids": ["cat_123"],
  "finding_ids": ["fnd_123", "fnd_456"],
  "title": "Reduce checkout SQL latency",
  "objective": "Reduce the latency contribution of the checkout digest.",
  "success_criteria": "A comparable Clinic window shows at least 50% lower total latency without a regression in error rate.",
  "owner": "sql-governance",
  "severity": "high"
}
```

The equivalent scoped endpoint is `POST /api/v1/catalog-items/{id}/treatments`; the path Catalog Item
is added to the Treatment scope.

## Move Between Stages

`POST /api/v1/treatments/{id}/transition`

```json
{
  "stage": "planning"
}
```

Every lifecycle action writes a Timeline event with the exact domain-action timestamp. This includes
creation, stage transition, observation start, completion, cancellation, and reopen. The Treatment
list exposes `stage_entered_at` and `stage_age_hours`, derived from that history; consumers must not
infer historical transitions from `updated_at`.

## Add Records

`POST /api/v1/treatments/{id}/records`

Records combine structured fields with Markdown. Typical Treatment Records are analysis, plan,
execution, observation, outcome, postmortem, and comments. Completion evidence must be linked to the
same Treatment.

### Customer delivery milestone

The server records `recommendation_shared` exactly once for a Proposal Record when all three fields
are true:

- `record_type=proposal_record`
- `visibility=customer_visible`
- `review_status=reviewed`

The milestone timestamp is the Record domain timestamp. On the first delivery, an active Treatment
in `assessment` or `planning` also advances to `alignment`, making the customer-pending state
explicit. Moving a Treatment into `alignment` by itself does not imply customer delivery, and merely
creating a draft Proposal Record does not count as delivery.

## Start Observation

The Treatment must first be in `execution`.

`POST /api/v1/treatments/{id}/observations/start`

```json
{
  "record_id": "rec_observation_123",
  "observation_due_at": "2026-07-20T08:00:00Z"
}
```

`record_id` must identify a linked `observation_record`. The due time must be in the future.

## Complete A Treatment

`POST /api/v1/treatments/{id}/complete`

| Outcome | Resulting state | Required evidence |
| --- | --- | --- |
| `fixed` | `completed` | Reviewed Observation Record with `conclusion_type=fixed`. |
| `improved` | `completed` | Reviewed Observation Record with `conclusion_type=improved`. |
| `unchanged` | `completed` | Reviewed Observation Record with `conclusion_type=unchanged`. |
| `not_optimizable` | `completed` | Ready or reviewed Outcome Record. |
| `accepted_risk` | `completed` | Ready or reviewed Outcome Record. |
| `failed` | `completed` | Reviewed failed/regressed observation or a ready Outcome Record. |
| `cancelled` | `cancelled` | Ready or reviewed Outcome Record. |
| `superseded` | `completed` | `superseded_by_treatment_id` sharing at least one Catalog Item. |

```json
{
  "outcome": "improved",
  "outcome_record_id": "rec_observation_123"
}
```

Completion sets `stage=completed`, writes `completed_at`, records a Timeline event, and recalculates
the linked Catalog Item status. A Catalog Item remains `in_treatment` while any related Treatment is
still active.

## Reopen

`POST /api/v1/treatments/{id}/reopen`

```json
{
  "stage": "assessment"
}
```

Reopening clears the prior Outcome, completion timestamp, observation scheduling, and supersession
relation. It returns the Treatment to `active` and recalculates linked Catalog Item status.

## Query

- `GET /api/v1/treatments`
- `GET /api/v1/treatments/stats`
- `GET /api/v1/treatments/{id}`
- `PATCH /api/v1/treatments/{id}` for descriptive fields only

List filters include `state`, `stage`, `outcome`, `severity`, `owner`, `assignee`, `priority`,
`org_id`, `cluster_id`, `q`, and `observation_due`.

### Period analytics

`GET /api/v1/treatments/stats` accepts:

| Query | Type | Meaning |
| --- | --- | --- |
| `from` | ISO 8601 timestamp | Inclusive start of the reporting period. Defaults to seven days before `to`. |
| `to` | ISO 8601 timestamp | Exclusive end of the reporting period. Defaults to now. |
| `compare_from` | ISO 8601 timestamp | Optional inclusive start of an explicit comparison period. Must be supplied with `compare_to`. |
| `compare_to` | ISO 8601 timestamp | Optional exclusive end of an explicit comparison period. Must be supplied with `compare_from`. |
| `timezone_offset_minutes` | integer | Offset used to align daily buckets. |
| `org_id`, `cluster_id` | string or repeated values | Apply the same global scope as the Treatment list. |

The response includes:

- `period`, `comparison_period`, and `comparison_mode`. The mode is `previous_equal`,
  `previous_calendar`, or `custom`. A complete calendar month compares with the previous calendar
  month; an in-progress calendar month compares month-to-date with the same elapsed portion of the
  previous month.
- `summary`, `comparison`, and `deltas` for New, Reopened, Recommendations Shared, Completed,
  Cancelled, Closed, Successful, period-end Backlog, net Backlog change, and median completion time.
- `time_series` daily New, Reopened, Shared, Completed, Cancelled, and Closed event counts plus
  end-of-day active Backlog.
- `current_snapshot` for the current Treatment stock.
- `stage_health` with current count/age signals plus period entry count, exit count, and median time
  to leave each Stage.
- `distributions.active_age` for the current active stock, `distributions.started_cohort` for the
  state of Treatments created in the reporting period as of period end, and
  `distributions.closed_outcomes` for closure events in the reporting period.
- `successful_treatments` completed with `fixed` or `improved`, including linked Catalog Item summaries.

Backlog is reconstructed from `treatment_created`, `treatment_reopened`, `treatment_completed`, and
`treatment_cancelled` Timeline events. Event-flow metrics and current-stock metrics are deliberately
separate and must not be added together. `net_backlog_change` is `backlog_end - backlog_start`; because
reopened work is included, it does not necessarily equal `new_treatments - closed_treatments`.

`median_completion_time_hours` only uses Treatments completed during that period and measures from
their original creation to completion. Cancelled Treatments are excluded. A
`recommendation_shared` event is written once when a Proposal Record first becomes both `reviewed`
and `customer_visible`; later edits to that Record do not create duplicate delivery milestones. The
first event advances an active Assessment or Planning Treatment to Alignment.
