# Metrics Range Data-Server Endpoint Implementation Plan

This ExecPlan is a living document. Keep `Progress`, `Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` up to date as work proceeds.

Reference: `PLANS.md` at repository root. This plan must be maintained according to `PLANS.md`.

## Execution Protocol (Mandatory)

Execute subtasks strictly in sequence. Do not run multiple subtasks concurrently.

For each subtask, create a fresh subagent with non-inherited context. Provide only this plan, the target subtask, and the minimum repository context required for that subtask.

After each subtask, the parent agent must review and integrate the patch, run the listed validation commands for that subtask, commit that subtask, and then update `Progress` before starting the next subtask.

Do not begin the next subtask with known failing tests or incomplete required docs for the current subtask.

If a subtask fails validation, fix the subtask and re-run validation before committing.

operator prompt template:

`Implement docs/2026-04-05-metrics-range-data-server-endpoint-plan.md using fresh non-inherited subagents per subtask, sequentially, with parent review/integration, one commit per subtask, and Progress updates after each subtask commit.`

## Purpose / Big Picture

After this change, users can query data-server metrics from `clinic metrics range` without leaving the existing command surface. This enables node-level metrics (cpu/mem/network/disk class queries) through the `/clinic/api/v1/data/metrics` endpoint while preserving existing `metrics range` behavior by default.

Users opt in with `--data-server` (or `--ds`). Without those flags, `metrics range` continues to call the existing data-proxy metrics endpoint.

The change is intentionally scoped to `metrics range` only. `metrics query` and `metrics series` remain unchanged in this milestone.

## Progress

- [x] (2026-04-05 21:44 CST) S1: Add endpoint selection behavior in `metrics range` with `--data-server` and `--ds`, including `--pool` incompatibility validation.
- [x] (2026-04-05 21:57 CST) S2: Add/adjust metrics tests for path, headers, metadata resolution, and conflict validation.
- [x] (2026-04-05 22:07 CST) S3: Update help and docs to reflect the new mode and run the verification ladder.
- [x] (2026-04-05 22:08 CST) Verification ladder complete: focused `Metrics` and `Help` tests plus `make verify` pass.

## Surprises & Discoveries

- Observation: `make verify` initially failed `legibility-check` because the plan used `Operator prompt template` (capitalized) and the checker matches lowercase `operator prompt template` literally.
  Evidence: `docs/2026-04-05-metrics-range-data-server-endpoint-plan.md must include an operator prompt template for explicit delegation authorization.`

## Decision Log

- Decision: Add a boolean endpoint selector (`--data-server`) with alias `--ds` on `metrics range`.
  Rationale: Minimal UX change and no command-surface split.
  Date/Author: 2026-04-05 / User + Codex

- Decision: Keep current endpoint as default; data-server mode is opt-in.
  Rationale: Avoid regressions for existing scripts and dashboards.
  Date/Author: 2026-04-05 / User + Codex

- Decision: Scope this change to `metrics range` only.
  Rationale: User requested integration there first; smaller blast radius.
  Date/Author: 2026-04-05 / User + Codex

- Decision: Resolve `X-OrgID` automatically from selected-profile metadata when possible, then from cluster lookup API fallback.
  Rationale: No new required flags/env vars for users.
  Date/Author: 2026-04-05 / User + Codex

- Decision: Reject `--pool` together with `--data-server`.
  Rationale: Prevent ambiguous semantics and accidental misrouting.
  Date/Author: 2026-04-05 / User + Codex

- Decision: Keep output and step contracts unchanged in data-server mode.
  Rationale: Preserve UX consistency (`echarts` default, existing `--output` values, existing `--step` behavior).
  Date/Author: 2026-04-05 / User + Codex

## Outcomes & Retrospective

Implementation met the planned scope: `metrics range` now supports an opt-in data-server path via `--data-server`/`--ds`, while default behavior and other metrics subcommands remain unchanged.

The test suite now covers request path/header contracts, metadata resolution short-circuit/fallback behavior, output routing parity in data-server mode, and conflict validation with `--pool`.

Help text and user-facing docs were aligned to the new mode, including explicit scope guardrails that `metrics query` and `metrics series` are unchanged.

## Context and Orientation

Current `metrics range` implementation in `internal/cmd/metrics.go` always builds a request to:

- `/data-proxy/metrics/<resolved-cluster-id>/api/v1/query_range`

The command already supports:

- range defaults and time parsing via shared helpers,
- `--pool` parent-id behavior for premium clusters,
- output routing (`echarts` default, `json`, `tui`),
- 504 retry behavior.

Relevant files:

- `internal/cmd/metrics.go` for parsing, request construction, retries, output routing.
- `internal/cmd/cluster.go` for cluster metadata resolution (`resolveClusterReferenceByID`, profile-first + API fallback behavior).
- `internal/cmd/metrics_test.go` for metrics command contract tests.
- `internal/cmd/help.go` and `internal/cmd/help_test.go` for command help contract.
- `README.md` and `docs/COMMAND_SURFACE.md` for user-facing and agent-facing behavior docs.

Data-server mode request contract from this plan:

- Method: `GET`
- Path: `/clinic/api/v1/data/metrics`
- Query params: `query`, `start`, `end`, `step`, optional `timeout`
- Headers:
  - `X-OrgType: cloud`
  - `X-OrgID: <resolved org id>`
  - `X-ClusterID: <resolved cluster id>`

## Plan of Work

### Subtask S1: Endpoint Selection and Request Construction

Update `internal/cmd/metrics.go` in `runMetricsRangeWithHooks` to parse `--data-server` and `--ds`.

If data-server mode is enabled:

- reject when `--pool`/`-p` is also enabled with a clear validation error,
- resolve cluster reference using existing `resolveClusterReferenceByID(ctx, resolvedClusterID)` to obtain `orgID`,
- build a `clinic.Request` targeting `/clinic/api/v1/data/metrics`,
- set required headers (`X-OrgType`, `X-OrgID`, `X-ClusterID`),
- keep existing query parameter behavior and existing retry/output logic.

If data-server mode is not enabled:

- keep existing request behavior unchanged (including pool resolution path and endpoint).

No changes to `metrics query` or `metrics series`.

### Subtask S2: Command Tests for Data-Server Mode

Add and adjust tests in `internal/cmd/metrics_test.go` to cover:

- `--data-server` routes to `/clinic/api/v1/data/metrics`,
- `--ds` alias behaves identically,
- required headers are set with expected values,
- selected-profile metadata short-circuits API lookup when valid,
- metadata lookup fallback is used when selected-profile metadata is unavailable/mismatched,
- `--pool` and `--data-server` conflict produces a deterministic error and does not issue the data-server request,
- existing output-routing tests continue to hold for data-server mode.

Keep existing tests green without changing unrelated expectations.

### Subtask S3: Help and Documentation Alignment

Update:

- `internal/cmd/help.go` (`metrics range` help text) to document `--data-server` and `--ds`, endpoint purpose, and `--pool` incompatibility.
- `internal/cmd/help_test.go` expected help snippets for metrics range.
- `README.md` metrics section with examples for data-server mode.
- `docs/COMMAND_SURFACE.md` metrics notes with the new mode contract.

Do not change other command-family docs unless required by test failures.

## Concrete Steps

All commands run from repository root:

`/Users/jujiajia/code/tidbcloud/clinic-cli`

1. Implement S1 and run focused metrics tests.

    go test ./internal/cmd -run Metrics -count=1 -v

Expected: existing metrics tests pass; new request-shape tests can be added in S2.

2. Implement S2 and re-run metrics tests.

    go test ./internal/cmd -run Metrics -count=1 -v

Expected: new data-server tests pass with deterministic path/header/conflict assertions.

3. Implement S3 and run help tests.

    go test ./internal/cmd -run Help -count=1 -v

Expected: help text assertions pass with updated metrics range contract.

4. Run full verification.

    make verify

Expected: legibility checks and full test suite pass.

## Validation and Acceptance

Acceptance is satisfied when all statements below are true:

1. Running `metrics range` without `--data-server/--ds` still hits `/data-proxy/metrics/<id>/api/v1/query_range`.
2. Running `metrics range --data-server` hits `/clinic/api/v1/data/metrics` with `X-OrgType`, `X-OrgID`, `X-ClusterID` headers.
3. Running `metrics range --ds` is equivalent to `--data-server`.
4. Running `metrics range --data-server --pool` fails fast with a clear incompatibility error.
5. `metrics query` and `metrics series` behavior is unchanged.
6. `metrics range` output mode behavior is unchanged (`echarts` default; `json`, `tui`, `echarts` all valid as before).
7. `make verify` succeeds.

## Idempotence and Recovery

Test commands in this plan are safe to re-run. Re-running them should not alter repository-tracked files.

If any subtask introduces regressions, revert only the subtask-local edits manually and re-apply the subtask in smaller increments. Do not use destructive git resets that could discard unrelated working-tree changes.

If endpoint behavior is partially implemented (for example path switched but headers missing), stop and complete the same subtask before moving forward. Do not progress with known contract gaps.

## Artifacts and Notes

During implementation, add concise evidence under this section:

- command outputs for `go test ./internal/cmd -run Metrics -count=1 -v`,
- command outputs for `go test ./internal/cmd -run Help -count=1 -v`,
- command outputs for `make verify`,
- any notable request-shape assertion snippets (path + headers) from tests.

Keep evidence brief and focused on proving behavior.

S1 evidence:

- `go test ./internal/cmd -run Metrics -count=1 -v` (PASS)
  - confirms no regression in existing metrics behavior while adding `--data-server` request selection logic.

S2 evidence:

- `go test ./internal/cmd -run Metrics -count=1 -v` (PASS)
  - covers `--data-server`/`--ds` path and headers, selected-profile metadata short-circuit, API fallback cases, output-mode routing parity checks, and `--data-server` + `--pool` conflict behavior.

S3 evidence:

- `go test ./internal/cmd -run Help -count=1 -v` (PASS)
  - verifies updated `metrics range` help contract, plus guardrails that `metrics query` and `metrics series` help output do not advertise `--data-server`/`--ds`.

Verification evidence:

- `go test ./internal/cmd -run Metrics -count=1 -v` (PASS)
- `go test ./internal/cmd -run Help -count=1 -v` (PASS)
- `make verify` (PASS, after adjusting plan phrase to include literal `operator prompt template`)

## Interfaces and Dependencies

Command interface additions:

- `clinic metrics range --data-server`
- `clinic metrics range --ds`

No new top-level commands, no config schema changes, no new environment variables.

Key internal dependency reuse:

- `resolveClusterReferenceByID` in `internal/cmd/cluster.go` for org resolution.
- Existing `clinic.Request` struct with `Headers` for data-server request headers.
- Existing metrics retry and output routing code paths in `internal/cmd/metrics.go`.

Request contract in data-server mode:

- `clinic.Request.Method = GET`
- `clinic.Request.Path = /clinic/api/v1/data/metrics`
- `clinic.Request.Query` contains `query/start/end/step` and optional `timeout`
- `clinic.Request.Headers` contains:
  - `X-OrgType=cloud`
  - `X-OrgID=<org id>`
  - `X-ClusterID=<cluster id>`

## Revision Notes

- 2026-04-05: Updated Progress/Artifacts/Outcomes with completed subtask evidence, recorded the legibility-check discovery, and normalized the execution-protocol phrase to include literal `operator prompt template` so `make verify` passes.
