Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/content/docs/factories/factory-dashboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@ A factory opens on its **Dashboard** page, covered next. **Factory definition**

## Read metrics on the Dashboard page

**Dashboard** is the factory's landing page. It summarizes the factory over a date range you choose:

* **Autonomy** - The share of the factory's merged PRs that needed no human input beyond an approving review and the merge itself. A PR counts as autonomous only if no person added commits, requested changes, or otherwise edited it before merge.
* **PR cycle time** - The median time the factory's merged PRs took from run kickoff through PR, first review, and merge, with a median for each stage.
* **Cost per PR** - The median cost of PRs opened in the range. Treat it as a lower-bound estimate: it can miss some run usage and does not match billing. See [Measure and improve a factory](/factories/measure-and-improve/) for its limitations.

The page also charts opened versus merged PRs and a breakdown of runs, and the **Cost per PR** card expands to list the most expensive PRs in the range. When Scorers are set up, Scorer cards summarize recent classification results.
**Dashboard** is the factory's landing page. It summarizes the factory over a date range you choose: Total runs, Pull requests (opened and merged), Autonomy, Cycle time, and Cost per PR (which expands to list the most expensive PRs in the range). When Scorers are set up, Scorer cards summarize recent classification results. See the [Metrics reference](/factories/metrics-reference/) for what each metric counts, how it's computed, and its data-coverage limits.

## Track work items on Activity

Expand Down Expand Up @@ -93,4 +87,5 @@ For a file-managed factory, `runners/*.yaml` in the repository is the source of
* [Definitions as code](/factories/factory-as-code/) - Define agents, automations, runners, and source ownership in code.
* [Factory agents](/factories/factory-agents/) - What each default agent does and how to configure it.
* [Measure and improve a factory](/factories/measure-and-improve/) - Configure the Scorers and benchmarks behind the **Dashboard** page.
* [Metrics reference](/factories/metrics-reference/) - What each **Dashboard** metric counts, how it's computed, and its data-coverage limits.
* [Troubleshooting Warp Factories](/factories/troubleshooting/) - Fixes for setup problems, work that doesn't start, and stuck runs.
20 changes: 1 addition & 19 deletions src/content/docs/factories/measure-and-improve.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,7 @@ Warp Factories tracks what your factory produces and how well it performs, so yo

## Read metrics on the Dashboard page

The **Dashboard** page shows activity, cost, autonomy, and evaluation results:

| Metric | What it shows |
| --- | --- |
| **Total runs** | All agent runs, with breakdowns by agent type, status, source, model, and more. |
| **PRs opened** | Pull requests created from factory work. |
| **PRs merged** | Pull requests that merged. |
| **Autonomy** | The share of the factory's merged PRs that needed no human input beyond an approving review and the merge itself. A PR counts as autonomous only if no person added commits, requested changes, or otherwise edited it before merge. |
| **PR cycle time** | The median time the factory's merged PRs took from run kickoff through PR, first review, and merge, with a median for each stage. |
| **Cost per PR** | An estimate of credits spent per pull request. |
| **Most expensive PRs** | The highest-cost pull requests. |
| **Scorer cards** | Results from your Scorers. |
| **Self-improvement PRs** | The three newest Self-improvement pull requests, regardless of the selected date range. |

**Cost per PR** is an estimate, not a billing figure: it counts recorded credits and can undercount actual usage.

:::caution
**PRs merged**, **Autonomy**, **PR cycle time**, and the detail in **Most expensive PRs** require the GitHub App and only cover activity from after you install it.
:::
The **Dashboard** page shows activity, cost, autonomy, and evaluation results over a date range you choose: **Total runs**, **Pull requests** (opened and merged), **Autonomy**, **Cycle time**, **Cost per PR** (with a Most expensive PRs drill-down), and Scorer cards. For what each one counts, how it's computed, and its data-coverage limits, see the [Metrics reference](/factories/metrics-reference/).

Use the **Dashboard** page to pick which runs to investigate, not to conclude what caused a change. **Total runs** includes evaluation, benchmark, and Self-improvement runs, so a higher run count with a flat PR count could mean harder tasks, retries, or measurement activity.

Expand Down
92 changes: 92 additions & 0 deletions src/content/docs/factories/metrics-reference.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: Factory Dashboard metrics reference
description: >-
Look up what each Dashboard metric counts, how Warp computes it, and its
data-coverage limits, from Total runs to Cost per PR.
sidebar:
label: "Metrics reference"
---

This reference describes every metric on a factory's **Dashboard** page: what it counts, how Warp computes it, and the data-coverage limits that shape how to read it. For where these metrics fit into a broader measurement workflow, see [Measure and improve a factory](/factories/measure-and-improve/).

## How to read these metrics

A few things apply across most cards on the page:

* **Cost per PR and Cycle time headline a median — the dashboard's other headlines are different kinds of numbers.** Costs and durations are heavily skewed by outliers, so those two cards report the middle value of the distribution instead of an average (with an even number of values, the median averages the two middle ones). Total runs and Pull requests headline plain counts, Autonomy headlines a ratio, and Scorer cards headline a pass rate.
* **Cards count PRs by different points in time.** **Pull requests** counts by when a PR was opened; **Autonomy** and **Cycle time** count by when a PR merged; **Cost per PR** counts every PR opened in the range regardless of merge status. The same date range can legitimately show different totals across cards — this reflects what each metric measures, not a data error.
* **Some PR detail needs a connected code host; some comes from the run itself.** Autonomy, Cycle time, PRs merged, and four columns in Most expensive PRs — title, status, diff stats, and the autonomy badge — come from webhooks on your connected code host: the Warp GitHub App on GitHub repositories, or the group webhook Warp installs when you [connect GitLab](/factories/integrations/gitlab/). Coverage starts only after that connection existed, so a PR from before then shows blank in those fields (an `owner/repo#123` reference stands in for a missing title). A PR's cost, creator, source, and requested model come from the run itself, so those keep showing regardless of code-host coverage.

## Total runs

**Total runs** counts every run your factory's agents executed whose creation time falls in the selected range, including subruns launched by other runs — each run and subrun counts individually toward the headline. Deleted runs don't count.

Beneath the headline, a secondary line shows the range's **top-level runs**: runs a person or a trigger started directly, with no parent. This is the number the **By source** breakdown view sums to, since a subrun inherits no trigger source of its own.

The view dropdown redraws the chart as a stacked area chart across six dimensions: **By agent type** (the default), **By status**, **By source**, **Top-level vs subruns**, **By model**, and **By harness**. Self-improvement runs appear as their own group under **By agent type**. Each view fetches only that dimension's counts, so switching views is fast and never re-runs the cost calculations behind Cost per PR. Hovering a point on the chart shows every group's exact count and its share of that bin's total; the legend below the chart names the groups but doesn't repeat the numbers.

Across every view, a run whose dimension value is missing or unresolvable groups under **Unknown**. The **By model** view additionally caps at the top eight models by total, folding the rest into a single **Other** group — unless that fold would hide just one model, which is shown on its own instead.

**Total runs** includes evaluation, benchmark, and self-improvement runs alongside the runs that produce pull requests, so a rising run count with a flat PR count can mean harder tasks, retries, or measurement activity rather than more output.

## Pull requests

The **Pull requests** chart plots two series over time:

* **Opened** counts distinct pull requests your factory's runs attached as artifacts. A PR is identified by its URL and counts exactly once, ever, in the bin where it first appeared — regardless of how many runs or subruns later reference it, and even if it's reported again inside a later range.
* **Merged** shows, of the PRs opened in a given bin, how many later merged — a cohort of the opened line, bucketed by the day the PR was **created** (or its merge day, if creation was never observed). A PR created before the selected range never counts here, even if it merges inside the range, and a recent bin's merged count can rise later as more of its open PRs merge.

Opened and merged use different identity pipelines — opened counts distinct PR-artifact URLs from run data, merged counts webhook-observed PR facts — so the two numbers aren't just imperfectly correlated: a period's merged count can occasionally read **higher** than its opened count for that same period, because a webhook can observe a merge for a PR that the run-artifact pipeline never captured as opened. Merged reads zero for repositories without a webhook connection, and for merges that happened before Warp started collecting PR facts.

## Autonomy

**Autonomy** is the share of the factory's merged pull requests that needed no human code push before merging. Warp counts a human opening the PR (which pushes the initial branch) as a code push, which is what keeps a human-authored PR that a factory run later revised from reading as autonomous — comments, reviews, requested changes, and the merge action itself never count as a push.

The card's funnel — **Merged PRs**, **From this factory**, and **Autonomous** — breaks the ratio down step by step:

* **Merged PRs** is every PR merged in the range across the factory's configured repositories, whoever created it.
* **From this factory** narrows that to the PRs this factory's runs produced.
* **Autonomous** narrows further to the subset whose full open history Warp observed (so it can prove nobody touched the PR) and which had no human code push. The headline ratio divides by this observed subset, not by every factory PR — a PR whose open event predates webhook collection can't be proven autonomous either way, so it's excluded from the ratio even though it still counts as a factory merge.

Membership in this funnel is counted by **merge time**, not by when the PR was opened — unlike the Pull requests chart's opened series. This is deliberate: it lets the card describe exactly what merged inside the selected range.

## Cycle time

**Cycle time** reports how long the factory's merged pull requests took to move through the pipeline, as four independent medians: **Kickoff → PR**, **PR → first human review**, **first human review → merge**, and the headline **Kickoff → merge**. Membership is counted by merge time, the same as Autonomy.

Kickoff is the creation time of the earliest factory run linked to the PR. First review is the earliest review from a human reviewer with a recorded time — bot and GitHub App reviews (agent reviewers, CI checks) never start this stage, but every human review state counts, including approvals. Each stage's median covers only the PRs where both of that stage's endpoints were observed, so the three stage medians do **not** sum to the headline — they're independent distributions, each with its own sample size. A stage reads as a dash when no merged PR in the range has both of its endpoints recorded, never as zero.

The two review-anchored stages depend on your code host delivering review webhooks; without that coverage, they're legitimately unmeasured rather than fast.

## Cost per PR

**Cost per PR** headlines the **median** attributed cost of the pull requests opened in the selected range — merged and unmerged PRs count alike, unlike the merge-time cards above. A secondary line shows the range's total cost and PR count.

Cost attribution works at the level of a **run tree** — a run plus every subrun it launched. If any run in a tree produced a PR, the entire tree's cost attributes to that PR. When one tree produces several distinct PRs, its cost splits evenly across them, so a credit is never counted toward more than one PR — but it does mean a range's summed PR costs can include a share of a tree whose other PRs fall outside that range.

Cost breaks down into three components — **compute**, **platform**, and **inference** — each converted from credits to US dollars at your team's current credit price. That conversion is an approximation, not a billing figure: it uses today's rate rather than the rate at the time the credits were spent, and credit recording isn't complete on every run, so the figures are a lower bound on true cost.

The card's view picker swaps its chart between two breakdowns of the same per-PR costs:

* **Cost breakdown** (the default) plots one line per cost component, each the bin's median of that component's own per-PR distribution. The three component medians are independent of each other and of the headline — they don't sum to it, because a median has no component decomposition. A bin with zero PRs plots as a gap in every line, never a zero, since an undefined median isn't the same as a free PR.
* **By PR size** groups the same per-PR costs by the pull request's size — additions plus deletions under 100 lines is **S**, under 500 is **M**, under 1,000 is **L**, and anything larger is **XL** — and plots a median cost line per size. This buckets the size of the diff, not engineering complexity. PRs whose line counts were never observed (no webhook coverage, or the PR predates fact collection) don't belong to any size bucket. When none of the range's PRs have observed line counts, the chart area reads "0 of N PRs have observed line counts" (or "No sized PRs in this range" when the range has no PRs at all) instead of drawing a chart; when only some do, the chart draws normally with a footnote reading "Sized N of M PRs"; when every PR in the range is sized, the chart draws with no footnote at all.

### Most expensive PRs

Below the chart, **Most expensive PRs** lists the 20 costliest pull requests first seen in the range, most expensive first. Each row shows the PR's status, who kicked off the run, the trigger source, a model mix (a bar sized by each model's share of the PR's inference cost, or the requested model as plain text when no per-model usage data exists), diff stats, and — when the PR's open event was observed — whether it was autonomous, using the same no-human-code-push definition as the Autonomy card. The section is collapsed by default and loads its data only once expanded, since the underlying query is expensive.

A PR's cost, creator, source, and requested model come from the run itself, so those still show for PRs that predate PR-fact collection. Title, status, diff stats, and the autonomy badge come from webhook-collected PR facts instead: a pre-collection PR shows its `owner/repo#123` reference in place of a title, and the rest of those columns read as a dash.

## Scorer cards

When a factory has Scorers configured, one card per Scorer appears at the bottom of the Dashboard, each showing its pass rate over the selected range alongside a trend chart and the agents it evaluates. A card reads "No scores in this range" when the range has no scored conversations — this covers the whole Dashboard range, not a fixed recent window, so it means the range itself has nothing scored rather than that the Scorer has never run. See [Configure Scorers](/factories/measure-and-improve/#configure-scorers) to set one up.

## Self-improvement pull requests

Self-improvement pull requests aren't a Dashboard card — they're tracked on the factory's own **Self-improvement** page, which lists every pull request self-improvement opened regardless of the Dashboard's date range. See [Configure and review Self-improvement](/factories/measure-and-improve/#configure-and-review-self-improvement) for how to turn it on and review its output.

## Related pages

* [Factory dashboard](/factories/factory-dashboard/) - An orientation to the whole factory dashboard, including the **Dashboard** page's place in it.
* [Measure and improve a factory](/factories/measure-and-improve/) - How Dashboard metrics fit alongside Scorers, benchmarks, and Self-improvement.
* [Connect GitHub to your factory](/factories/integrations/github/) and [Connect a factory to GitLab](/factories/integrations/gitlab/) - Set up the code-host connection that PR-level metrics depend on.
1 change: 1 addition & 0 deletions src/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ export const sidebarTopics: StarlightSidebarTopicsUserConfig = [
items: [
{ slug: 'factories/factory-dashboard', label: 'Factory dashboard' },
{ slug: 'factories/measure-and-improve', label: 'Measure and improve' },
{ slug: 'factories/metrics-reference', label: 'Metrics reference' },
],
},
// Troubleshooting sits outside the groups, last in the tab. It was in
Expand Down
Loading