# v0.2 Observability Monitoring 接入规格

本文定义 HWLAB `v0.2` 接入 G14 共享 Prometheus 监控基础设施的应用侧规格。G14 监控基础设施本身由 UniDesk 长期参考 `docs/reference/g14-observability-infra.md` 管理；HWLAB 只声明业务服务如何暴露指标、如何被发现、如何查询和如何验收。

## 在系统中的职责划分

- G14 共享监控控制面运行在 `devops-infra` 平台基础设施 namespace，由 UniDesk/G14 基础设施规格管理。它承载 Prometheus Operator、Prometheus 实例、可选 Alertmanager/Grafana 以及跨 namespace scrape 选择策略。
- `hwlab-v02` 只承载 HWLAB 业务服务、`/metrics` endpoint、Service labels/ports、`ServiceMonitor` / `PodMonitor` 和 `PrometheusRule`。不得把 Prometheus Operator、Prometheus、Grafana 或 Alertmanager 部署进 `hwlab-v02`。
- `hwlab-node-v02` Argo Application 仍只同步 `deploy/gitops/node/runtime-v02` 到 `hwlab-v02`。监控控制面不能挂到这个 Application；它只消费业务 namespace 中的监控声明。
- `hwlab-cli` 或 UniDesk 受控 CLI 可以作为查询入口，但必须通过 runtime namespace/lane 自动解析目标，不得手动暴露 Prometheus 公网地址。

## 内部架构

应用指标路径按 Kubernetes 原生监控模型收敛：

```text
hwlab-* service
-> GET /metrics
-> Service named port / labels
-> ServiceMonitor in hwlab-v02
-> Prometheus in devops-infra
-> controlled CLI / proxy query
```

第一阶段优先使用 `ServiceMonitor`，因为 v0.2 保留服务均有 ClusterIP Service。动态 Job、AgentRun runner 或临时 debug Pod 的指标如需接入，后续使用 `PodMonitor`，但不得把 AgentRun runner 变成 HWLAB 自有运行面。

所有 HWLAB `/metrics` endpoint 必须是内部指标入口，不参与公网 FRP 暴露。第一阶段使用独立 `metrics` named Service port 暴露 sidecar 指标；公网 FRP 仍只转发业务端口，所以 `19666/19667` 上的 `/metrics` 必须继续是负向结果。`hwlab-cloud-web` 和 `hwlab-edge-proxy` 不得把 `/metrics` 代理给普通浏览器或公网 API 调用方。Prometheus 抓取路径只允许从集群内 Service 访问。

第一阶段已采用 metrics sidecar 方式接入。sidecar 读取服务名、namespace、gitops target、业务 health URL 和超时配置，对外只监听集群内 `metrics` named port。业务容器不需要直接承担 Prometheus 文本生成逻辑，但每个被接入服务必须提供稳定的内部 health endpoint，让 sidecar 生成 `hwlab_service_health_probe_success`。

sidecar 脚本通过 ConfigMap 挂载时，Deployment template 必须包含脚本内容 hash annotation。任何 metrics sidecar 脚本、目标 URL、端口或模板化配置变化都应触发 pod rollout；不能只更新 ConfigMap 后等待 kubelet 投影刷新，也不能把“Prometheus 能 scrape 到旧 sidecar”当成新逻辑已生效。

Cloud Web 用户感知性能必须进入同一套 Prometheus 查询面。浏览器侧 RUM 只上报低基数 route template、metric、method、status class、outcome 和数值，不上报 trace/session/conversation/thread/run/job/user ID 或正文。`hwlab-cloud-api` 负责接收 `/v1/web-performance`、做进程内聚合，并仅允许 `hwlab-cloud-api` pod 内 loopback 访问 `/v1/web-performance/metrics`；`hwlab-cloud-api` 的 metrics sidecar 再通过额外 loopback target 把 WebUI Prometheus 文本附加到 9100 `/metrics`。公网 `19666/19667` 仍不得暴露 Prometheus 原始文本。

Cloud Web 顶级性能页通过同源 `GET /v1/web-performance/summary` 读取低基数 JSON 摘要，用于展示用户可感知的 WebUI 样本数、慢 API route p95、Web Vitals、long task 和错误/超时问题队列。该接口不得返回 Prometheus 原始文本、Secret、prompt/assistant 正文或 trace/session/conversation/thread/user 等高基数标识；CLI 同路径验收使用 `hwlab-cli client request GET /v1/web-performance/summary`，不直连 Prometheus 公网地址。

观测面不得污染被观测对象。Cloud Web 性能页自身（`/performance` / `#/performance`）不得启动 workspace hydrate、live refresh、HWPOD node-ops、agent conversations 等业务请求，也不得把性能页自身的 LCP、Navigation Timing、Long Task 或 `/v1/web-performance*` 请求写入 WebUI 业务性能样本。Cloud API 在 `/v1/web-performance` 入库时必须丢弃来自性能页或观测 API 的样本，作为旧 bundle、缓存客户端或探针误上报的兜底。

## API 接口说明

### `/metrics`

保留服务应逐步暴露 Prometheus 文本格式指标：

| 服务 | 第一阶段指标 | 说明 |
| --- | --- | --- |
| `hwlab-cloud-api` | HTTP request count/latency、DB readiness/query latency、Code Agent submit/result/trace latency、AgentRun dispatch status、provider profile terminal status | 核心业务 authority，优先接入。 |
| `hwlab-cloud-web` | HTTP request count/latency、static asset/proxy latency、upstream timeout/error count | 只记录同源代理与静态服务指标。 |
| `hwlab-edge-proxy` | HTTP proxy request count/latency、upstream status、timeout/error count | 证明公网 edge 到 cloud-api 的性能。 |
| `hwlab-agent-skills` | health/list/upload/tree/file request count/latency、error count | 技能包服务指标。 |
| `hwlab-deepseek-proxy` | bridge request count/latency、upstream status、model/readiness probe result | 不记录 prompt、response 或 upstream token。 |

Cloud Web RUM 指标使用以下稳定前缀：

- `hwlab_webui_performance_sample_total`：Cloud API 接收并接受的浏览器性能样本计数。
- `hwlab_webui_performance_duration_seconds`：Navigation Timing、LCP、INP/FID 近似、Long Task 和业务 API 请求耗时 histogram。
- `hwlab_webui_layout_shift_score`：CLS histogram。

这些指标必须至少带 `service="hwlab-cloud-web"`、`namespace`、`gitops_target`、`kind`、`metric`、`route`、`method`、`status_class` 和 `outcome` 标签。`route` 必须是模板化路径，例如 `/v1/agent/chat/result/:id`，不能是原始 result/trace/session URL。

指标命名使用稳定前缀 `hwlab_`。HTTP route 标签必须使用 route template，例如 `/v1/agent/chat/result/:traceId`，不得使用原始 URL。推荐基础标签：

- `service`
- `namespace`
- `route`
- `method`
- `status_class`
- `provider_profile`
- `operation`
- `terminal_status`

禁止把这些值作为 label：

- `traceId`
- `sessionId`
- `conversationId`
- `threadId`
- `runId`
- `commandId`
- `jobId`
- 用户 ID、API key ID、prompt、assistant text、device output、SecretRef value

这些高基数或敏感数据继续留在 trace/result/inspect、日志尾部或 issue 验收证据中，不进入 Prometheus label。

sidecar 必须至少暴露以下基础指标：

- `hwlab_service_up`：sidecar 进程自身可服务时为 `1`。
- `hwlab_service_health_probe_success`：sidecar 对业务 health endpoint 的最近一次探测成功时为 `1`，失败时为 `0`。

`hwlab_service_up=1` 只能证明 metrics sidecar 存活，不能证明业务容器健康；关闭监控接入 issue 时必须同时验证 `hwlab_service_health_probe_success=1`。

### `ServiceMonitor`

`deploy/gitops/node/runtime-v02` 应生成或包含 v0.2 业务服务的 `ServiceMonitor`。Selector 必须同时约束：

- namespace 为 `hwlab-v02`
- `hwlab.pikastech.local/gitops-target=v02`
- `hwlab.pikastech.local/monitoring=enabled`
- 具体 `hwlab.pikastech.local/service-id`

`ServiceMonitor` 不得选择 `hwlab-dev`、`hwlab-prod`、`agentrun-v01` 或任意无关 namespace。跨 namespace 抓取策略由 G14 共享 Prometheus 控制面决定，HWLAB 只提供带标签的声明。

### `PrometheusRule`

HWLAB v0.2 可声明 `PrometheusRule`，但规则只表达当前 v0.2 目标行为和性能观测，不作为新的发布 gate。第一阶段建议规则：

- `hwlab-cloud-api` request p95/p99 latency。
- Code Agent submit/result terminal latency。
- AgentRun dispatch failure rate by provider profile。
- edge-proxy upstream 5xx/timeout rate。
- HWPOD node-ops failure/blocker rate。

规则命名和 label 必须能定位 lane、namespace、service 和 operation；不要把单个 trace/run/job 写入规则。

## 安全与暴露边界

- `/metrics` 不需要经过公网 FRP；公网 `19666/19667` 不应返回 Prometheus 原始文本。
- 如果未来给 `/metrics` 增加 bearer token，Secret 必须只记录 SecretRef 名称和 key，不能出现在文档、日志、issue 或 metric label 中。
- Prometheus 读取 HWLAB 指标不等于拥有 HWLAB Secret、DB URL、provider key 或用户 API key 读取权限。
- `hwlab-v02` 业务 namespace 不持有 Prometheus Operator 集群管理凭证，也不部署共享 Prometheus control-plane。

应用接入实现不得引入以下回归：

- 让 GitOps artifact replacement 重写 `hwlab-metrics` sidecar image。
- 让 mounted ConfigMap 脚本变化缺少 Deployment template hash，导致 pod 不滚动。
- 用 Node `fetch` 或其他在目标运行面不稳定的全局 HTTP client 作为唯一 health probe 实现；probe client 应使用当前 runtime 中可稳定验证的 HTTP/HTTPS request 路径。
- 只验证 `up{namespace="hwlab-v02"}`，不验证业务 health probe 指标。
- 把 `/metrics` 透传到 `19666/19667` 公网入口。

## 测试规格

## T1

阅读本文和 UniDesk `docs/reference/g14-observability-infra.md`，然后用 CLI 手动测试以下内容：查询 G14 k3s 当前 CRD、namespace 和 `devops-infra` 对象，确认共享监控控制面如果存在则位于平台基础设施 namespace，不在 `hwlab-v02` 业务 service matrix 中。

## T2

阅读本文，然后用 CLI 手动测试以下内容：对每个已接入服务执行集群内 `GET /metrics`，确认 HTTP 200、Prometheus 文本格式、包含 `hwlab_` 前缀基础指标，且响应不包含 Secret、prompt、assistant text、device output 或高基数 ID。

## T3

阅读本文，然后用 CLI 手动测试以下内容：读取 `deploy/gitops/node/runtime-v02` 或 live `hwlab-v02` 对象，确认 `ServiceMonitor` selector 限定 `hwlab-v02`、`gitops-target=v02`、`monitoring=enabled` 和具体 service id；确认不存在把 Prometheus、Grafana 或 Alertmanager 部署到 `hwlab-v02` 的对象。

## T4

阅读本文，然后用受控 CLI 或集群内查询测试以下内容：Prometheus 中 `up{namespace="hwlab-v02"}` 能看到已接入服务 target，基础延迟/错误率 PromQL 能返回结果，并确认公网 `http://74.48.78.17:19666/metrics` 和 `http://74.48.78.17:19667/metrics` 不暴露原始指标。

## T5

阅读本文，然后用受控 CLI 或集群内查询测试以下内容：Prometheus 中 `hwlab_service_up{namespace="hwlab-v02"}` 和 `hwlab_service_health_probe_success{namespace="hwlab-v02"}` 的结果数量与已接入服务数量一致，且每个结果值均为 `1`。如果 `up=1` 但 `hwlab_service_health_probe_success=0`，应优先排查 sidecar 到业务 health endpoint 的协议、URL、超时和运行时 HTTP client，而不是判定 Prometheus 基础设施故障。

## T6

阅读本文，然后用 CLI 手动测试以下内容：检查已接入 pod 的容器状态，确认每个目标 pod 都包含 ready 的 `hwlab-metrics` sidecar 且 restartCount 没有异常增长。对 ConfigMap 承载的 sidecar 脚本或 render 模板做改动后，必须确认对应 Deployment 发生了新的 pod rollout。

## T7

阅读本文和 [spec-v02-hwlab-cloud-web.md](spec-v02-hwlab-cloud-web.md)，然后用真实浏览器或 repo-owned live DOM probe 访问 `http://74.48.78.17:19666/#/workspace`，触发 Cloud Workbench 首屏和同源业务 API 请求；随后通过受控 Prometheus 查询确认 `hwlab_webui_performance_sample_total{namespace="hwlab-v02"}` 有样本，且 `histogram_quantile` 能基于 `hwlab_webui_performance_duration_seconds_bucket` 计算 `/workspace` LCP 或 `api_request` p95。若 sidecar 基础 target 正常但 WebUI 指标无样本，或者只有 `/performance` / `#/performance` 观测页自身样本，不能关闭 WebUI 性能监控 issue。

## 规格的实现情况

| 规格项 | 状态 | 说明 |
| --- | --- | --- |
| 应用侧监控接入边界 | 已实现 | HWLAB 只负责 metrics sidecar、ServiceMonitor/PrometheusRule 和受控查询；共享 Prometheus control-plane 不在 `hwlab-v02`。 |
| G14 共享监控控制面 | 已实现 | 由 UniDesk/G14 基础设施规格定义，默认位于 `devops-infra`。 |
| v0.2 服务 `/metrics` | 已实现 | 第一阶段接入 `hwlab-cloud-api`、`hwlab-cloud-web`、`hwlab-edge-proxy`、`hwlab-agent-skills`、`hwlab-deepseek-proxy`。 |
| ServiceMonitor / PrometheusRule | 已实现 | 已进入 v0.2 GitOps desired state；规则用于观测，不作为发布旧门禁。 |
| 受控查询与验收 | 已实现 | 通过 UniDesk `hwlab g14 observability status|query` 和集群内边界检查验证 target discovered、health probe 可用和公网不暴露。 |
| Cloud Web 用户感知性能 | 已实现 | 浏览器 RUM 经 `/v1/web-performance` 聚合为 `hwlab_webui_*` 指标，由 `hwlab-cloud-api` sidecar 附加导出，关闭 issue 前必须用 `19666` Web 入口触发并在 Prometheus 中看到样本。 |
