# description
Wrapper shape for REST responses under `/api/*` (Step 14.2). Three variants distinguished by the `kind` discriminator and which payload field is present (`items` for list kinds, `item` for single-resource kinds, `value` for `kind: 'config'`). The `/api/scan` and `/api/health` responses are exempt — they carry the underlying `ScanResult` / `IHealthResponse` shape directly. The `/api/graph` response is also exempt — it returns the formatter's native textual output (text/plain or text/markdown). Step 14.5.d adds the required `kindRegistry` field on every payload-bearing variant so the UI can render Provider-declared kinds (label, color, icon) without hardcoding visuals; sentinel kinds (`health`, `scan`, `graph`) stay exempt because they don't carry an envelope payload. The change keeps `schemaVersion` at `'1'` — the BFF is greenfield (no released consumers run against `'1'` without `kindRegistry`), so a versioned migration buys nothing.

# properties.schemaVersion.description
Envelope shape version. Bumped only on breaking changes. The Step 14.5.d addition of `kindRegistry` keeps the version at `'1'` because there are no released consumers in the wild.

# properties.kind.description
Discriminator. List kinds (`nodes`, `links`, `issues`, `plugins`) carry `items`. The `node` kind carries `item`. The `config` kind carries `value`. The `health` / `scan` / `graph` values are reserved for documentation parity with the routes that DON'T use this envelope.

# properties.items.description
Present when `kind` is one of the list kinds (`nodes`, `links`, `issues`, `plugins`). Empty array is valid and means the filter matched zero rows.

# properties.item.description
Present when `kind` is `'node'`. Single-resource envelope payload.

# properties.value.description
Present when `kind` is `'config'`. Carries the merged effective config object.

# properties.filters.description
Echo of the URL filters the server applied, normalized into a JSON-friendly shape (arrays for multi-value filters, `null` for absent ones). Helps the client correlate the response with the request.

# properties.kindRegistry.description
Catalog of node kinds active in the current scope, keyed by kind name. Built once per server boot from every enabled Provider's `kinds` map and embedded into every payload-bearing envelope so the UI can render kind tags / palette swatches / graph nodes against Provider-declared visuals (label, color, icon) without ever hardcoding a closed kind enum. Sentinel envelopes (`health`, `scan`, `graph`) are exempt.

# properties.kindRegistry.additionalProperties.properties.providerId.description
Id of the Provider that contributed this kind. Lets the UI scope kind ownership and disambiguate when two Providers happen to declare the same kind name (kernel surfaces this as `provider-ambiguous` but the UI may still receive the merged registry during the conflict window).

# properties.counts.properties.total.description
Total rows after filtering, before pagination is applied.

# properties.counts.properties.returned.description
Rows actually carried in `items` (≤ `limit`).

# properties.counts.properties.page.description
Pagination window. Present when the endpoint paginates (today: `/api/nodes` only).

# properties.counts.description
Tally + paging info. Present on every list / single envelope; absent on `health` / `scan` / `graph` responses (which don't use this envelope).

# oneOf[].description
List envelope — `items` payload + `counts` + `kindRegistry`.

# oneOf[].description
Single-resource envelope — `item` payload + `kindRegistry`, no `counts` / `filters`.

# oneOf[].description
Value envelope — `value` payload + `kindRegistry`, no `counts` / `filters`.

# oneOf[].description
Sentinel kinds — reserved for routes that do NOT carry an envelope payload at the wire level (`health`, `scan`, `graph`). They do not carry `kindRegistry` either; clients that need it must call any payload-bearing endpoint at boot.