Project productivity metrics
Project reports use one captured set of selected canonical repositories for the current period, previous period, and trend. A repository added recently can contribute retained earlier PRs to all three windows. Membership before the disclosed history baseline is unknown.
For the reporting workflow, see View Project Productivity. For scope and attribution, see Project reports.
Metric definitions
In these formulas, N is the distinct eligible merged-PR count, Ns is the count with usable native scores, P is their summed native points, and A is the set of canonical people with eligible merged PRs. R counts accepted exclusively attributed original Gateway requests. C is accepted exclusively attributed estimated cost; C(A) restricts that cost to people in A. G is the set of canonical people with compatible attributed AI activity.
| Metric | Calculation | Availability rule |
|---|---|---|
| Productivity points | P | Pending or recomputing scores remain disclosed. |
| Merged PRs | N | Deduplicate native PR IDs across the selected repositories. |
| Active contributors | Size of A | Unlinked authors withhold the complete-person count. |
| Points per active contributor | P / size of A | Requires a complete person denominator. |
| Average scored PR points | P / Ns | Pending PRs enter N, but not Ns. |
| Repository or contributor share | Its points / P, or its PRs / N | Uses the full selected Project denominator. |
| Active repositories | Distinct selected repositories with PR activity by the contributor | AI-only associations do not count. |
| Estimated spend | C | Missing usage is unknown; accepted free usage can be zero. |
| Cost per 1,000 points | 1,000 × C / P | Requires compatible filters, usable scores, pricing, attribution, and retained evidence. |
| Requests per PR | R / N | Uses original requests, including eligible MCP requests without a price event. |
| Cost per PR | C / N | Requires qualified spending and a compatible PR population. |
| Points per estimated dollar | P / C | Requires complete usable scores and qualified spending; zero cost is unavailable. |
| Cost per active contributor | C(A) / size of A | Excludes AI-only people's spend; missing active-person cost withholds the average. |
| AI activity among active contributors | Size of the intersection of G and A / size of A | Requires complete canonical-person and compatible activity coverage. |
Zero or unknown denominators produce Not available, never infinity. These operational ratios do not establish PR causality, saved labor, billing totals, or ROI. Values are pooled from the full selected population; repository averages are never averaged together.
Backend spending and filter boundaries
The Project UI hides cost information. The backend retains the following spending rules and derived metrics.
Accepted Project cost equals the union of accepted exclusive repository allocations. Shared across Project repositories, shared across the Project boundary, and unresolved references remain excluded. Model and provider breakdowns are separate views of the same cost; do not add them together. Overlapping Projects are not additive.
Gateway and Observer are separate sources. Observer Project spending remains unavailable without trusted repository attribution. Historical session lifetime totals cannot supply selected-period spending or trends.
Repository and linked-person selections can narrow output and spending together. PR work type, target branch, and delivery exclusions narrow output and PR evidence; spending remains on all work types. Incompatible ratios and AI activity comparisons are unavailable.
Scope and display limits
| Setting | Behavior |
|---|---|
| Repository selection | Up to 1,000 canonical repositories; search and paging preserve selection. |
| Quiet repositories | Remain in the selected set and repository table. |
| Custom period | At most 366 civil days in the reporting timezone. |
| Overview | Four cards, paged contributor/repository productivity lists, four selected-period timelines, and one repository table. |
| Detail | Output rankings, contributors, work mix, PR scores, reviews, and sessions load on demand. Cost and Investment remain backend-only. |
| Qualified ranking preview | Three highest and three lowest entries; fewer than six appear once in one list. |
| Search and paging | Change displayed rows without changing full-scope totals or the ranking population. |
| Refresh | Creates a new capture; membership, access, source-policy, or evidence changes can invalidate an older report. |
Reporting calendar
Periods use the administrator's saved reporting timezone and preference revision, resolved by the native Outcomes context. Custom start and end dates are inclusive local dates; source intervals include their start and exclude their end. A current period stops at its captured cutoff. Daylight saving changes can make a local day 23 or 25 hours; seven civil days need not equal 168 hours.
Comparisons retain the same selected repository set. Rolling and custom periods compare the same number of preceding civil days. Calendar month, quarter and year presets retain their calendar boundaries. To-date comparisons use the same local wall-clock progress, clipped to the prior calendar period. A timezone preference change requires a newly authorized context and report; it does not reinterpret an accepted report's buckets.
Administrator API
All Project routes require a currently active administrator account and return
Cache-Control: no-store. Report requests do not modify Project configuration.
Start by obtaining a native context with POST /api/v1/outcomes/analytics/context,
using scope: {kind: "project", id: "PROJECT_ID"}, the selected period,
prFilters and current preferenceRevision. The server resolves timezone,
authorization, membership and evidence revisions; client fields cannot establish
trusted identities or costs.
| Endpoint | Purpose |
|---|---|
GET /api/v1/project-productivity/projects/{id}/repositories | Read current canonical repository selection metadata. |
POST /api/v1/project-productivity/reports | Capture a new overview root. |
POST /api/v1/project-productivity/reports/{id}/views | Request a derived view of the accepted root. |
GET /api/v1/project-productivity/reports/{id} | Poll a job, read its first page, or follow its signed cursor. |
DELETE /api/v1/project-productivity/reports/{id} | Cancel the authenticated owner's retained computation. |
Repository selectors
The selection endpoint accepts search, offset, limit (10, 25 or 50), and an
optional expected revision. It returns the full ordered canonical
repositoryIds, full matchingIds, the visible items, selectionDigest,
repositoryRedirects, membership counts and historyKnownFrom. Searches and
visible pages do not define the selected set. A changed expected revision returns
context_stale; reload membership before applying another selection.
Report parameters.projectId must match the context. Without a compact selector,
filters.repositoryIds: null uses the full Project; an array selects an explicit
subset, and [] selects none. Saved predecessor IDs are resolved by the server;
repository names and reused names do not establish canonical membership.
For a compact selection, send
repositorySelection: {scopeDigest: "SELECTION_DIGEST", bits: "BASE64URL_BITS"}
and filters.repositoryIds: []. Bits refer to the complete returned
repositoryIds order, with the least significant bit selecting the first ID in
each byte. Encode exactly ceil(repositoryIds.length / 8) bytes as unpadded
base64url; unused final bits must be zero. The digest must match the current full
canonical set. It is a consistency check, not an access token. The server
independently authorizes and expands the selection. This supports up to 1,000
repositories within the unchanged 64 KiB JSON request limit.
Requests and retained pages
A report body contains version: 1, adapter: "project_productivity_v1",
contextToken, section, parameters and limit (1–50). POST routes accept no
query parameters. Parameters include the Project selector, normalized filters,
source, trendMetric, sortMetric, descending and search (at most 256 UTF-8
bytes). selectedPeriodTrend: true requests the selected-period series;
monthlyTrend controls the alternative trend. Supported retained sections are
overview, points, investment, reviews, sessions, output_rankings and
spending_rankings; cost sections remain backend-only in the Project UI.
Selected-period highlight series
By default, an overview contains one series for the requested trendMetric.
Existing requests and clients keep that representation. To request all four
selected-period highlights in one new overview root, send the single request
header X-AIC-Project-Highlight-Series: 1 and keep the existing JSON body, with
parameters.selectedPeriodTrend: true. The requested trendMetric must be one
of productivity_points, gateway_requests, five_minute_peak_sessions, or
merged_prs.
A supporting server acknowledges the request with
X-AIC-Project-Highlight-Series: 1 on the initial successful HTTP 200 or 202
response. Keep that acknowledgement while polling the returned job. Its
header.series contains exactly these four metric keys, in the order above,
for the same current window, captured population, basis, and interval plan.
Validate every series and its metric identity, unit, status, coverage, and
intervals before displaying or caching the bundle. Missing, duplicate,
out-of-order, or partial bundles are invalid; unavailable values retain their
status and reason rather than becoming zero.
Bundled highlights use native application/json, not the existing single-series
compact report-page representation. Omit Accept, send application/json, or
include an acceptable JSON or wildcard range. A compact-only bundle submission
returns HTTP 406 before creating a job. Request JSON on every poll and page;
changing a completed bundle's read to compact-only also returns 406, without
changing or deleting the retained result. A JSON read of that same job still
works. Legacy single-series reports retain compact transport support.
The equivalent native report parameter is highlightSeries: true; it also
requires selectedPeriodTrend: true and the same overview metric scope.
Absent or false preserves the default one-series response. For compatibility
with older servers that strictly decode request bodies, use header negotiation
rather than adding this parameter to the browser's JSON body. Repeated or
unknown header values, other sections, and derived-view requests are rejected.
Ranking, table, and detail requests keep their existing parameters.
If an older server ignores the request header and sends no acknowledgement, expect exactly one series and load the other highlights through the existing sequential derived views of that root. Do not retry the root to negotiate support. This fallback supports a new client talking to an older serving backend; it does not guarantee that a retained job using the new representation can be routed between arbitrary older and newer server versions.
A pending response is HTTP 202 with its job id and expiry. Poll the GET route
for that job, honoring Retry-After. A completed page contains header, rows,
totalCount and nextCursor. The header retains context, basis, typed metrics,
coverage, counts and series. Null metrics remain unavailable with their reasons.
Follow a page with GET /api/v1/project-productivity/reports/{id}?cursor=...,
using the job that issued that cursor. A derived view has its own job ID; use that
ID for its pages while retaining the original root for subsequent view requests.
Send cursors unchanged and URL-encoded. Offsets, repeated cursors, forged cursors
and cursors from a different owner or view are rejected. DELETE accepts no query
parameters. Protected jobs are account-bound even after an email rename or reuse.
Sorting, searching, paging and supported evidence views preserve the accepted root's population and cutoff. Explicit Refresh creates a new root. Expiry, access revocation, changed membership or destructive evidence changes can invalidate an older report; obtain a fresh context and capture again. A capacity failure is an error, not permission to truncate the population.