---
title: Delivery Insights
---

# Delivery Insights

:::warning[Alpha]
Delivery Insights is an alpha feature. It is disabled by default and must be opted into, it may contain bugs that become apparent once enabled, and it has not been tested across every OpenChoreo deployment topology. Its API and stored schema may change incompatibly in a later release without notice.
:::

Delivery Insights reports the four DORA metrics — Deployment Frequency, Lead Time for Changes, Change Failure Rate and Mean Time to Recovery — for the components OpenChoreo deploys, at namespace, project or component scope, sliced by environment.

## DORA Metrics

| Metric                    | Answers                                  | Derived from                                           |
| ------------------------- | ---------------------------------------- | ------------------------------------------------------ |
| **Deployment Frequency**  | How often do we ship?                    | Rollouts that reached a healthy state                  |
| **Lead Time for Changes** | How long from commit to running?         | Commit authoring time to rollout ready time            |
| **Change Failure Rate**   | How often does shipping break something? | Failed rollouts, and incidents attributed to a rollout |
| **Mean Time to Recovery** | How long until we are healthy again?     | Incidents, from trigger to resolution                  |

Each metric comes back with its value, a DORA classification (Elite, High, Medium, Low), a trend against the previous window of equal length, and a time-bucketed series at daily, weekly or monthly granularity.

The Observer folds delivery events and incidents into durable facts on a timer, then pre-computes the rollups the API serves. Aggregation runs every five minutes, so a deployment appears in the metrics on the next tick rather than immediately.

## Prerequisites

- An observability plane installed and registered as an `ObservabilityPlane`. See [Observability & Alerting](https://openchoreo.dev/docs/platform-engineer-guide/observability-alerting.md).
- The [observability-logs-opensearch](https://github.com/openchoreo/community-modules/tree/main/observability-logs-opensearch) logs module, version `0.6.0` or later. It is the only logs module that serves the delivery events sweep today.

## Enabling Delivery Insights

Two independent flags, both off by default, and **both are required**. One collects the data; the other shows the page.

### Step 1: Collect the metrics in the Observer

export const deliveryInsightsObserverEnable = `helm upgrade openchoreo-observability-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-observability-plane \\
  --version 1.3.3 \\
  --namespace openchoreo-observability-plane \\
  --reuse-values \\
  --set observer.featurePreview.deliveryInsights.enabled=true`;

```bash
{deliveryInsightsObserverEnable}
```

The Observer creates its delivery insights tables on startup and begins aggregating. While the flag is off it does not open the store at all, so an installation that never enables the feature carries none of its tables.

### Step 2: Show the page in the portal

export const deliveryInsightsPortalEnable = `helm upgrade openchoreo-control-plane oci://ghcr.io/openchoreo/helm-charts/openchoreo-control-plane \\
  --version 1.3.3 \\
  --namespace openchoreo-control-plane \\
  --reuse-values \\
  --set backstage.features.deliveryInsights.enabled=true`;

```bash
{deliveryInsightsPortalEnable}
```

With this off, **Delivery Insights** is absent from the portal navigation and the page renders a disabled notice if reached by URL.

## Lead Time Needs Commit Provenance

Lead Time for Changes measures from when a commit was authored. OpenChoreo cannot discover that timestamp on its own, so whatever produces the Workload has to record it:

```yaml
spec:
  source:
    commit: <commit SHA, hex, 7 to 40 characters>
    branch: <branch the commit was built from>
    repository: <repository URL>
    authoredAt: <RFC3339 timestamp>
```

Only `commit` and `authoredAt` feed the metric; `branch` and `repository` are provenance for reading a deployment back later. Without them the other three metrics are unaffected, and lead time reports reduced **commit coverage** rather than an estimate.

### Native CI

**Nothing to configure.** The shipped builders — `dockerfile-builder`,
`paketo-buildpacks-builder`, `gcp-buildpacks-builder`,
`ballerina-buildpack-builder` — already carry provenance end to end. A component
built by one of them reports lead time without any extra setup.

They do it in two steps. `checkout-source` resolves the commit and reads its
author timestamp:

```bash
COMMIT_AUTHORED_AT=$(git show -s --format=%aI HEAD)
```

publishing `commit-sha`, `source-branch` and `commit-authored-at` as output
parameters. `generate-workload` then passes them to `occ workload create`.

If you write your own CI workflow, wire those four parameters through to
`generate-workload` the way the shipped builders do:

```yaml
- name: generate-workload
  arguments:
    parameters:
      - name: source-commit
        value: "{{steps.checkout-source.outputs.parameters.commit-sha}}"
      - name: source-branch
        value: "{{steps.checkout-source.outputs.parameters.source-branch}}"
      - name: source-repository
        value: "{{workflow.parameters.git-repo}}"
      - name: source-authored-at
        value: "{{steps.checkout-source.outputs.parameters.commit-authored-at}}"
```

A workflow that leaves them out still builds and deploys. It just produces
Workloads with no provenance, and those deployments count towards every metric
except lead time.

### External CI

A pipeline outside OpenChoreo passes the same four values as flags on
`occ workload create`:

```bash
occ workload create \
  --namespace acme-corp \
  --project online-store \
  --component product-catalog \
  --descriptor workload.yaml \
  --image "$IMAGE" \
  --source-commit "$(git rev-parse HEAD)" \
  --source-branch "$BRANCH" \
  --source-repository https://github.com/my-org/my-repo \
  --source-authored-at "$(git show -s --format=%aI HEAD)"
```

Run it in the checked-out repository, at the commit the image was built from —
both `git` commands read the working tree rather than anything OpenChoreo
provides. In a container-based pipeline, use the CLI image:
`ghcr.io/openchoreo/openchoreo-cli:v1.3.1`.

:::caution[The flags need `occ` v1.3.0 or later]
`--source-commit` and `--source-authored-at` were added with Delivery Insights.
An older `occ` rejects them as unknown flags, or — depending on how your pipeline
handles a non-zero exit — silently publishes a Workload with no provenance. Run
`occ workload create --help` and check the flags are listed before relying on them.
:::

Four things to get right:

- **Use the author date, `%aI`.** Not the committer date (`%cI`), which a rebase
  rewrites, and not the build time, which would make every deployment look
  instantaneous.
- **`--source-authored-at` must be RFC3339.** `git show -s --format=%aI` produces
  exactly that, offset included; OpenChoreo normalises it to UTC on the way in, so
  a commit authored `2026-09-24T18:08:30+05:30` is stored as
  `2026-09-24T12:38:30Z`.
- **`--source-commit` must be a SHA.** It is validated as 7 to 40 hex characters,
  so a branch or tag name is rejected rather than stored as provenance pointing at
  nothing. A short SHA is accepted; native CI records the full 40.
- **Provenance travels with the image.** When a build updates an existing
  Workload, `spec.source` is replaced along with `spec.container.image`. Leaving
  the previous build's commit attached to a new image would report a lead time
  that is simply wrong.

### Checking that it worked

Three places to look, in the order the value travels.

**1. The Workload carries it.**

```bash
kubectl get workload <component>-workload -n <namespace> -o jsonpath='{.spec.source}'
```

```json
{
  "authoredAt": "2026-09-24T12:38:30Z",
  "branch": "main",
  "commit": "8c41917b38ed76c37510922864a906774deb578e",
  "repository": "https://github.com/openchoreo/sample-workloads"
}
```

An empty result means the producer did not pass the flags. Nothing downstream can
recover it.

**2. The deployment event carries it.** Delivery events are recorded in the data
plane namespace for that project and environment, not in the control plane:

```bash
kubectl get events -A --field-selector reason=DeploymentSucceeded \
  --sort-by=.lastTimestamp \
  -o jsonpath='{.items[-1:].message}'
```

The payload should show `commit` and `commitAuthoredAt`. If `spec.source` was
populated but these are absent, the rollout predates the Workload update.

**3. The metric reports full coverage.** After the next five-minute aggregation
tick, query the component and check `coverage` — the fraction of deployments in
the window carrying provenance:

```json
"leadTime": { "p50Ms": 939646600, "coverage": 1, "classification": "Medium" }
```

`coverage: 1` means every deployment counted. A value below 1 means some
deployments of that component reached the metrics without provenance, and the
reported lead time describes only the rest. `coverage: 0` with deployments
present means none of them carried it.

## Access

Reading the metrics requires the `deliveryinsights:view` action. The portal, the read API and the MCP tools all enforce it. By default it is granted by the `admin`, `platform-engineer`, `developer` and `sre` roles.

## Querying from an Agent

The observability plane MCP server exposes the metrics as two tools, so an agent can answer delivery questions without going through the portal. Both are served from the Observer's `/mcp` endpoint and enforce the same `deliveryinsights:view` action as the portal.

| Tool                     | Returns                                                                                                           |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `query_dora_metrics`     | The four metrics for a scope and window: value, classification, trend and a time-bucketed series                  |
| `query_dora_deployments` | The individual rollouts behind those numbers, with project, component, environment, commit, outcome and lead time |

Both require `namespace`, `start_time` and `end_time`, and narrow with `project`, `component` and `environment`. `query_dora_metrics` also takes `granularity` and a `metrics` list to compute a subset; `query_dora_deployments` takes `limit` and `sort_order`.

Classification depends on the length of the window. The same rollouts can read `Elite` over a week and `High` over a month, because the per-day rate falls as the window widens. Compare like windows.

See [MCP Servers](https://openchoreo.dev/docs/reference/mcp-servers.md) for connecting an assistant to the observability plane.

## Configuration Reference

### Observability Plane

| Value                                              | Default | Description                                                                   |
| -------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
| `observer.featurePreview.deliveryInsights.enabled` | `false` | Collect delivery metrics. Maps to `FEATURE_PREVIEW_DELIVERY_INSIGHTS_ENABLED` |

### Control Plane

| Value                                         | Default | Description                                                                              |
| --------------------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| `backstage.features.deliveryInsights.enabled` | `false` | Show the Delivery Insights page. Maps to `OPENCHOREO_FEATURES_DELIVERY_INSIGHTS_ENABLED` |
