# List Dedicated K8s Resources — Reference

Companion to `SUBSKILL.md`. Read when field semantics, limits, or errors are unclear.

Upstream: regional-server `K8sResourceService.ListK8sResources`.
DevOps: `POST /api/v1/devops/cluster/dedicatedK8sResources` (script path omits `/api/v1/devops`).

## Query (routing only)

Not forwarded into the regional-server body.

| Params | Rule |
|--------|------|
| `region` + `cloud_provider` | Use both (lowercased). `region` is the **logical** name (e.g. `us-west-2`), not enum `AWS_US_WEST_2`. |
| `cluster_id` | Alternative: Mgmt resolves region/cp; must be Dedicated. |
| Neither | 400: must provide region and cloud_provider, or cluster_id. |

**Convenience:** query `cluster_id` + body `planeType=DATA_PLANE` and empty
`dataPlane.clusterId` → handler injects query `cluster_id` into the body.

## Body (protojson camelCase)

Mirrors `ListK8sResourcesRequest`. One Kind per request.

| Field | Required | Notes |
|-------|----------|-------|
| `planeType` | yes | `CONTROL_PLANE` \| `DATA_PLANE` (not `UNSPECIFIED`) |
| `dataPlane` | DP | At least one of `projectId` / `clusterId`. Both set → `projectId` wins. Ignored on CP. |
| `gvk` | yes | `kind` required (PascalCase). `group` / `version` optional (server resolves). |
| `selector` | yes | May be `{}`. |
| `option` | no | Defaults below. |

### Selector

| Field | Behavior |
|-------|----------|
| `namespace` | Namespaced resources; empty without `name` may list all namespaces. |
| `name` | **Get-by-name**: ignores `label` and `field`; `maxItems` N/A. |
| `label` | Server-side label match (all pairs). |
| `field` | Client-side post-filter after List (AND). Dot path to scalar leaf (e.g. `status.phase`). Operators: `EQUALS`, `NOT_EQUALS`, `PREFIX`, `EXISTS`. `OPERATOR_UNSPECIFIED` rejected. |

### Option

| Field | Default | Notes |
|-------|---------|-------|
| `detail` | `false` | `false` → TEXT table (`kubectl get -o wide` style). `true` → YAML (sanitized/masked). |
| `events` | `false` | Only when `detail=true`. YAML wraps `{resource, events}`. |
| `maxItems` | server default | Summary: default 200, max 1000. Detail: default 20, max 100. No `page_token`. |

## Response

DevOps envelope plus:

| Field | Meaning |
|-------|---------|
| `content_type` | `TEXT` (summary) or `YAML` (detail). `JSON` enum exists upstream but is not implemented. |
| `content` | Serialized list/get result string. |
| `truncated` | Apiserver List hit `maxItems` (**before** `selector.field` filter). |
| `hints` | Non-fatal notes (truncation, field-filter shrinkage, partial events, etc.). |
| `item_count` | Items in `content` **after** field filter (not cluster total). |

## Policy (do not maintain a local allowlist)

- GK access is **deny-by-default** on the server.
- Disallowed group/kind or query-policy violations return API errors.
- Do not copy or invent Kind allowlists in this skill; retry with a different Kind or tighten selector after reading the error.

## Common Errors

| Situation | Typical result |
|-----------|----------------|
| Missing region/cp and cluster_id | 400: must provide region and cloud_provider, or cluster_id |
| Empty body | 400: request body is required |
| Invalid body JSON / protojson | 400: invalid request body |
| `cluster_id` not Dedicated | 400: cluster is not a dedicated cluster |
| Invalid / unregistered region | Often 500 from downstream region lookup |
| Kind/group not allowed or query policy fail | ParameterInvalid-style error from regional-server |
| Bad / missing token | 401/403 |

## Environments

| `env` | Backend |
|-------|---------|
| `prod` (default) | `https://prod.devops.pingcap.com` |
| `staging` | `https://staging.devops.pingcap.com` |
| `dev` | `https://dev.devops.pingcap.com` |
