Scanner performance API

GET /api/v1/scanner/performance provides a tenant-scoped, UI-consumable read model over durable Scanner records. It does not expose Prometheus samples to the browser and does not synthesize values for metrics Scanner cannot derive.

Authorization and tenancy

Response

{
  "tenantId": "62ebf136-e558-4772-b397-785a0e735dcb",
  "window": "6h",
  "from": "2026-07-16T13:00:00Z",
  "until": "2026-07-16T19:00:00Z",
  "observedAt": "2026-07-16T19:00:00Z",
  "metrics": {
    "queueDepth": {
      "value": 4,
      "source": "scanner.scan_runtime_state:Pending"
    },
    "scanDurationMs": {
      "sampleCount": 20,
      "p50": 1250,
      "p95": 4900,
      "source": "scanner.scan_metrics:non-replay"
    }
  },
  "omittedMetrics": [
    {
      "metric": "failureRate",
      "reason": "no immutable terminal outcome timestamp is recorded"
    }
  ]
}

The fields have deliberately narrow meanings:

An unsupported window returns 400. Authentication or scanner:read/legacy scanner.admin authorization failures return 401 or 403.

Future extension rule

Add a metric only after Scanner durably records the required source fields and a derivation test proves the window, tenant, replay, and missing-data behavior. Do not zero-fill an unavailable metric.