# PJ2026-01060508 Web哨兵

## 修改历史

| 版本 | 对应 commit id | 更新日期 | 变更说明 |
| --- | --- | --- | --- |

当前正文仍在规格治理草稿中；未定稿前不新增版本号，不为单次编辑追加 `待提交` 版本。

## 正文

## PJ2026-01060508 Web哨兵需求规格

## 1. 文档控制

| 字段 | 内容 |
| --- | --- |
| 编号 | PJ2026-01060508 |
| 短名 | Web哨兵 |
| 层级 | L3 子课题 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-25-p0-web-probe-sentinel; draft-2026-06-27-p0-workbench-read-model-rootcause |
| Dashboard 实现引用版本 | draft-2026-06-26-p8-web-probe-sentinel-recovery |
| 多实例实现引用版本 | draft-2026-06-26-p9-multi-web-probe-sentinel |
| Monitor Web 聚合实现引用版本 | draft-2026-06-26-p10-monitor-web-aggregation |
| Monitor Web 观察面板治理实现引用版本 | draft-2026-06-27-p11-monitor-web-observability-dashboard; draft-2026-06-27-p12-cadence-scheduler-monitor-web |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-010605 运维监控](PJ2026-010605-observability-monitoring.md) |
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010601 发布流水](PJ2026-010601-controlled-release.md)、[PJ2026-010602 源码同步](PJ2026-010602-source-sync.md)、[PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md)、[PJ2026-010604 公开入口](PJ2026-010604-public-entry.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |

本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版：正文只保留 Web 哨兵的稳定使命、范围、术语、系统边界、内部分工、目标图和原子需求。Web 哨兵是现有 `web-probe observe` 能力的生产化运行形态，不是新的探针实现。

## 2. 目的和范围

### 2.1 目的

Web哨兵负责把已经用于 HWLAB Cloud Web 原入口验收的顶层 `web-probe observe start/status/command/collect/analyze` 能力服务化为 YAML-first 生产哨兵，使平台能够持续观察 HWLAB Web public origin、Workbench 多轮任务、Trace/final/timing 投影和发布后恢复状态。

本规格的目标状态是：人工 CLI、常驻调度器、dashboard、maintenance API、CI/CD targetValidation 和后续 dry-run 都消费同一套 observe runner、control queue、artifact JSONL、`collect` 渲染和 `observe analyze` 报告。哨兵服务只负责编排、索引、展示和发布联动；它不得复制第二套 Playwright runner、DOM sampler、offline analyzer、finding classifier、Workbench 状态机或业务事实源。

Web哨兵必须遵循 UniDesk YAML-first ops。目标 node/lane、public origin、runtime namespace、image、PVC、ServiceAccount、Service、NetworkPolicy、scenario、cadence、prompt source、report view、retention、maintenance token、dashboard public exposure、CI/CD control-plane 和 Secret sourceRef 都必须来自 owning YAML 或 configRef。代码只解析引用、校验形状/类型/冲突并渲染受控计划；不得把 namespace、cadence、threshold、Secret、image、URL、profile 或 report view 写成隐藏默认。

### 2.2 范围内

- `web-probe observe` CLI 的 wrapper/adapter 边界，使常驻服务能够稳定调用 start/status/command/collect/analyze。
- YAML `observability.webProbe.sentinel.enabled/configRefs` 的 legacy 单实例入口，以及 `observability.webProbe.sentinels[]` 多实例 registry 与每个 sentinel 管理 YAML 的引用图。
- 常驻 TypeScript 单 Pod wrapper 服务、scheduler、scenario runner、PVC/SQLite index、health、metrics、maintenance API 和 dashboard。
- `sentinel plan|apply|status|validate|report|maintenance` 与 `sentinel image|control-plane` 等受控 CLI 入口。
- 发布流水 maintenance start/stop、quick verify、targetValidation、GitOps/Argo/git-mirror closeout 和 public exposure 验证。
- Dashboard 信息架构、规范化 API、前端组件分层、自动刷新、筛选、深链和 trace/turn 两层阅读视图。
- Vue `monitor-web` 观察面板的趋势曲线、固定视口三栏、运行时间线、cadence freshness、root cause 可见性和配套 CI/CD。
- `workbench-dsflash-go-tool-call-10x` 生产 canary 和 24 小时 dry-run 收口。
- `workbench-auth-session-switch-2users` 账号切换链路哨兵，覆盖账号 A/B 登录、登出、session 列表和 session 切换命令链。
- Secret、prompt、provider payload、artifact 和 dashboard 的脱敏边界。

### 2.3 范围外

- Workbench 会话、message/part、Trace 顺序、final response、steer/cancel 和 timing authority 的业务正确性仍由 [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义。
- AgentRun run/command/provider profile 的执行生命周期归 [PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) 和 [PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md)。
- API path、错误 envelope、route policy 和用户身份语义归 [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)。
- 第一阶段不交付分布式压测；loadtest 只保留同镜像、同 wrapper 的配置和命令扩展点。
- in-cluster 哨兵不是外部公网监控节点。若后续需要真正外网用户路径监控，应另行定义外部或边缘哨兵，不把当前服务伪装成外部观测点。
- 多实例 Web 哨兵不得用一个 Pod、一个 PVC 或一个 SQLite index 伪装隔离。共享 dashboard domain 可以按 route prefix 暴露，但 runtime Deployment、Service、PVC、SQLite、GitOps path、Argo Application、metrics label 和 report index 必须按 sentinel id 独立。
- SQLite index、dashboard、metrics 和 maintenance 状态不得替代 `samples.jsonl`、`control.jsonl`、network/artifact JSONL 或 `analysis/report.json` 成为探针事实源。
- Dashboard 不负责修复 Workbench projection、trace timing、runner/envreuse 或 git mirror 慢路径；它只把 observe/analyze 已采集事实组织成可读的值守和分析入口。

## 3. 术语表

| 术语 | 定义 |
| --- | --- |
| Web哨兵 | 常驻 wrapper/orchestrator，按 YAML 调度现有 `web-probe observe` CLI，对 HWLAB Web public origin 做持续 canary、分析、展示和发布联动。 |
| sentinel registry | node/lane root YAML 下的 `observability.webProbe.sentinels[]`，只声明 sentinel id、enabled 和管理 configRef。 |
| sentinel 管理 YAML | registry 项指向的 owning YAML，声明单个 sentinel 的 id、enabled、mode 和 runtime/workflow/promptSet/reportViews/publicExposure/cicd/secrets configRefs。 |
| sentinel id | 多实例哨兵的稳定小写标识，必须进入 CLI `--sentinel`、Kubernetes/GitOps label、metrics label、report index 和 dashboard route。 |
| 账号切换哨兵 | `workbench-auth-session-switch-2users`，使用两组 YAML Secret sourceRef 驱动登录、登出、session 列表和 session 切换链路。 |
| observe runner | 现有 `web-probe observe start` 启动的浏览器采样器；它写入 DOM、network、control、screenshot、artifact 等 JSONL。 |
| observe artifact | `web-probe observe` 产生的 stateDir、JSONL、截图、analysis/report.md 和 analysis/report.json，是哨兵报告的事实来源。 |
| CLI wrapper adapter | 服务与 CLI 共享的命令适配层，把 start/status/command/collect/analyze 表达为稳定调用，不复制 runner/analyzer 实现。 |
| sentinel run | 哨兵调度一次 scenario 产生的运行窗口，绑定 node/lane、scenario id、observer id、stateDir、report SHA、finding 摘要和维护窗口状态。 |
| scenario | YAML 声明的巡检或 quick verify 任务，包括 targetPath、cadence、sample interval、rounds、backend profile、promptSetRef、reportViewRef 和 analyze 阈值引用。 |
| configRef | 形如 `path/to/file.yaml#object.path` 的配置引用。root YAML 只保存启用状态和引用，具体值归 owning YAML。 |
| owning YAML | 拥有某类事实生命周期的 YAML 文件，例如 runtime、scenario、promptSet、reportView、publicExposure、CI/CD 或 Secret 分发。 |
| report view | YAML 声明的 summary、turn-summary、findings、trace-frame 和 raw artifact 读取策略，包括默认分页、最大分页和 redaction。 |
| synthetic prompt set | YAML 管理的合成 prompt 集。报告默认只展示 prompt id、hash、字节数和轮次编号，不展示原文。 |
| maintenance window | 发布或维护期间的哨兵状态：继续采样和记录，但暂停告警；结束时触发 quick verify 和 analyze。 |
| quick verify | 由 maintenance stop 或 CI/CD targetValidation 触发的一次短巡检，底层仍使用 `web-probe observe` CLI 和 `observe analyze`。 |
| SQLite index | PVC 上的轻量索引，只保存 run、scenario、finding、report hash、artifact 摘要和 dashboard 分页信息；它不是业务或探针事实源。 |
| dashboard workbench | 面向平台值守和问题分析的 Web 哨兵监控工作台，按 overview、runs、findings、run detail、trace-frame 等视图组织同一 report/index 数据。 |
| trace-frame viewer | Dashboard 内的第二层 trace 阅读视图，只从已有采样帧和 report view 渲染单帧文字版 trace，不另存截图或另造 analyzer。 |
| auto refresh | Dashboard 的受控刷新能力；刷新只读 API/report/index，不发送 control command、不启动采样、不制造第二事实源。 |
| public exposure | YAML 声明的 `monitor.pikapython.com` HTTPS 暴露，通过共享 PK01 Caddy + FRP managed-block helper 到达 ClusterIP Service。 |
| targetValidation | 发布流水中的目标验证结果；对 HWLAB Web 恢复的判定必须来自 observe/analyze 对 public origin 的观察，不得只看 Argo green。 |
| monitor-web | 独立于 sentinel-runner 的 Vue 3 + TypeScript + Vite 展示和聚合层，承载 `monitor.pikapython.com` root、多哨兵总览、趋势曲线、时间线、单哨兵详情和受控截图验收。 |
| cadence freshness | 根据 YAML cadence、scheduler heartbeat、latest run age、active/planned run 和 analyzed report 更新时间计算的运行新鲜度；它默认是非阻塞值守告警，只有真正导致 run/report 不产生或业务链路不可用时才升级为 blocker。 |
| env reuse | CI/CD 复用既有 env image、依赖缓存、BuildKit 层和未受影响服务的发布产物，以避免无关重建；小范围变更应在 status/closeout 中暴露 build/reuse 摘要。 |

## 4. 系统边界和接口

| 边界项 | 内容 |
| --- | --- |
| 外部使用者 | 平台值守人员、发布操作人员、Workbench owner、CI/CD targetValidation、问题调查 agent。 |
| 外部输入 | YAML configRefs、Secret sourceRef presence、HWLAB Web public origin、scenario cadence、maintenance 操作、observe artifacts、analyze reports、GitOps/Argo 状态。 |
| 受控资源 | Web哨兵 Deployment、Service、PVC、ServiceAccount、NetworkPolicy、ConfigMap、publicExposure、SQLite index、dashboard 和 Prometheus metrics。 |
| 外部输出 | sentinel status、health、metrics、dashboard overview、run history、finding analysis、run detail、report summary、turn-summary、trace-frame、maintenance 状态和 targetValidation 结果。 |
| 用户接口 | `bun scripts/cli.ts web-probe sentinel ...`、`https://monitor.pikapython.com` dashboard、CI/CD maintenance 调用和受控 GitOps/control-plane CLI。 |
| 系统边界 | Web哨兵只生产运行监控和发布恢复证据；不定义业务成功，不写第二套 Workbench 状态，不直接修复 Web，不读取或打印 Secret/prompt/provider payload。 |

## 5. 内部分工与规格索引

| 编号 | 内部模块 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
| --- | --- | --- | --- | --- | --- |
| PJ2026-0106050801 | Wrapper边界 | 本规格 6.1 | 只 wrap 现有 observe CLI，禁止第二 runner/analyzer | web-probe observe、Workbench唯一投影 | 服务化入口、人工排障 |
| PJ2026-0106050802 | YAML配置 | 本规格 6.2 | configRefs、owning YAML、parser 校验和 redacted plan | YAML运维、公开入口、Secret分发 | plan/status、部署渲染 |
| PJ2026-0106050803 | 常驻服务 | 本规格 6.3 | scheduler、scenario runner、PVC/SQLite、health、metrics、maintenance API | Wrapper边界、YAML配置 | dashboard、CI/CD |
| PJ2026-0106050804 | 报告视图 | 本规格 6.4 | CLI/report API 渐进读取、分页、redaction、trace-frame | observe collect/analyze、Workbench唯一投影 | issue evidence、dashboard |
| PJ2026-0106050805 | 发布集成 | 本规格 6.5 | CI/CD、GitOps、Argo、maintenance、targetValidation、publicExposure | 发布流水、源码同步、公开入口 | 发布恢复判定 |
| PJ2026-0106050806 | Canary验收 | 本规格 6.6 | dsflash-go 十轮工具调用、24 小时 dry-run 和 profile 结构化失败边界 | Agent编排、Workbench、web-probe | 生产巡检收口 |
| PJ2026-0106050807 | 安全隔离 | 本规格 6.7 | Secret/prompt/provider redaction、NetworkPolicy、public dashboard auth | 用户管理、平台运维 | 安全 closeout |
| PJ2026-0106050808 | 代码引用 | 本规格 6.8 | SPEC 头部标注和生成/配置追溯 | 规格治理 | 后续 PR 审计 |
| PJ2026-0106050809 | Dashboard工作台 | 本规格 6.9 | overview、runs、findings、run detail、trace-frame viewer、前端分层 | 报告视图、常驻服务、Workbench性能 | 平台值守和问题分析 |
| PJ2026-0106050810 | 多实例与账号切换 | 本规格 6.10 | sentinel registry、实例隔离、账号切换 command、route prefix 和 report label | YAML配置、Wrapper边界、安全隔离 | 多哨兵巡检、账号链路值守 |
| PJ2026-0106050811 | Monitor Web 聚合 | 本规格 6.11 | runner/web 职责拆分、单 monitor-web 聚合、Kubernetes discovery、Vue+TS 前端和 public exposure 收敛 | 多实例与账号切换、Dashboard工作台、发布集成 | `monitor.pikapython.com` 统一值守入口 |
| PJ2026-0106050812 | Monitor Web 观察面板治理 | 本规格 6.12 | 趋势曲线、运行时间线、固定视口三栏、cadence freshness、Vue CI/CD/env reuse/git mirror | Monitor Web 聚合、Dashboard工作台、发布集成、源码同步 | 可滚动上线和值守的统一观察面板 |

### 5.1 目标架构图

```mermaid
flowchart LR
  subgraph Config[UniDesk YAML source of truth]
    Lane[hwlab-node-lanes.yaml<br/>sentinels registry]
    Mgmt[sentinel management YAML]
    Runtime[runtime owning YAML]
    Scenario[scenario owning YAML]
    Prompts[synthetic prompt YAML]
    Report[report view YAML]
    Exposure[publicExposure YAML]
    Secrets[Secret sourceRef YAML]
    Lane --> Mgmt
    Mgmt --> Runtime
    Mgmt --> Scenario
    Mgmt --> Prompts
    Mgmt --> Report
    Mgmt --> Exposure
    Mgmt --> Secrets
  end

  subgraph Sentinel[Web哨兵 Pod]
    Scheduler[Scheduler]
    Adapter[observe CLI wrapper adapter]
    Index[(SQLite index on PVC)]
    API[/api overview status runs report views maintenance]
    Metrics[/metrics]
    Dash[Dashboard workbench]
    Scheduler --> Adapter
    Scheduler --> Index
    API --> Index
    Dash --> API
    Metrics --> Index
  end

  subgraph Observe[Existing web-probe observe]
    Runner[observe runner]
    Control[control queue]
    Art[(samples/control/network/artifacts JSONL)]
    Analyze[observe analyze]
    Runner --> Art
    Control --> Runner
    Art --> Analyze
  end

  subgraph Target[Observed system]
    Web[HWLAB Web public origin]
    API2[HWLAB Cloud API]
    AR[AgentRun backend profile dsflash-go]
    Web --> API2
    API2 --> AR
  end

  Scenario --> Scheduler
  Adapter --> Runner
  Adapter --> Control
  Analyze --> Index
  Runner --> Web
  Dash -. HTTPS .-> Exposure
```

### 5.2 配置引用图

```mermaid
flowchart TD
  Root[config/hwlab-node-lanes.yaml<br/>lanes.v03.targets.D601.observability.webProbe.sentinels[]] --> Entry[id/enabled/configRef]
  Entry --> Mgmt[sentinel management YAML#sentinel]
  Mgmt --> Refs[configRefs]
  Refs --> Runtime[runtime.d601-v03.yaml#sentinel.runtime]
  Refs --> Scenarios[scenarios.workbench.yaml#sentinel.scenarios]
  Refs --> PromptSets[prompt-set.dsflash-go.yaml#sentinel.promptSet]
  Refs --> ReportViews[report-views.yaml#sentinel.reportViews]
  Refs --> PublicExposure[public-exposure.d601-v03.yaml#sentinel.publicExposure]
  Refs --> Cicd[cicd.d601-v03.yaml#sentinel.cicd]
  Refs --> SecretRefs[secrets.d601-v03.yaml#sentinel.secrets]
  Scenarios --> PromptSets
  Scenarios --> ReportViews
  Scenarios --> AnalyzeThresholds[hwlab-node-lanes.yaml#...observe.analysisThresholds]
  PublicExposure --> Edge[PK01 Caddy + FRP managed block]
  SecretRefs --> Runtime
  Cicd --> Runtime
```

配置引用图必须保持单向：root YAML 只保存 enable 与 ref；具体数值在 owning YAML；parser 只解析、校验和报告，不写合并后的新 source of truth。

### 5.3 目标数据流图

```mermaid
flowchart TD
  Y[YAML configRefs] --> Plan[sentinel plan/status]
  Plan --> S[Sentinel scheduler]
  S --> OStart[observe start]
  S --> OCmd[observe command]
  OStart --> Artifacts[Observe artifacts JSONL]
  OCmd --> Artifacts
  Artifacts --> Collect[observe collect]
  Artifacts --> Analyze[observe analyze]
  Analyze --> ReportJson[analysis/report.json]
  Analyze --> ReportMd[analysis/report.md]
  ReportJson --> Index[SQLite index]
  ReportMd --> Index
  ReportJson --> ViewApi[bounded report view API]
  Index --> ReportCli[sentinel report]
  Index --> Dashboard[Dashboard]
  ViewApi --> Dashboard
  Index --> Metrics[Prometheus metrics]
  Index --> Validation[targetValidation]
```

`ReportCli`、dashboard、metrics 和 targetValidation 只能读取 artifact/report/index 摘要。它们不得重新访问 Workbench、重新采样页面、重排 trace 行、重新分类 finding 或从 SQLite 推导业务事实。

### 5.4 常规巡检时序图

```mermaid
sequenceDiagram
  participant Sch as Sentinel scheduler
  participant CLI as observe wrapper adapter
  participant Obs as observe runner
  participant Web as HWLAB Web public origin
  participant Ana as observe analyze
  participant Idx as SQLite/PVC index

  Sch->>CLI: observe start with YAML scenario
  CLI->>Obs: start sampler/stateDir
  Obs->>Web: passive sample and screenshots
  Sch->>CLI: observe command newSession/selectProvider/sendPrompt
  CLI->>Obs: enqueue control command
  Obs->>Web: official UI/API action
  Sch->>CLI: observe status until terminal/window end
  Sch->>Ana: observe analyze stateDir
  Ana-->>Idx: report SHA and findings summary
```

### 5.5 发布 maintenance 时序图

```mermaid
sequenceDiagram
  participant CI as CI/CD Pipeline
  participant Sen as Sentinel API
  participant CP as Runtime control-plane
  participant CLI as observe wrapper
  participant Ana as observe analyze

  CI->>Sen: maintenance/start release id
  Sen-->>CI: sampling continues, alert muted
  CI->>CP: rollout / Argo sync
  CP-->>CI: runtime healthy summary
  CI->>Sen: maintenance/stop
  Sen->>CLI: quick verify observe start/command/status
  CLI-->>Sen: observer/run/stateDir
  Sen->>Ana: analyze quick verify artifact
  Ana-->>CI: report SHA, findings, targetValidation status
```

### 5.6 哨兵自身 rollout 时序图

```mermaid
sequenceDiagram
  participant CP as Sentinel control-plane
  participant GitOps as GitOps repo
  participant Argo as ArgoCD
  participant Pod as Sentinel Pod
  participant Val as sentinel validate

  CP->>GitOps: publish digest-pinned manifests
  Argo->>Pod: sync Deployment/Service/PVC
  Val->>Pod: /api/health
  Val->>Pod: /metrics
  Val->>Pod: dashboard/public exposure probe
  Pod-->>Val: scheduler heartbeat and PVC writable
```

哨兵自身 rollout 只验证哨兵服务健康、配置装载、PVC/SQLite 可写、metrics、dashboard 和调度循环；它不能把另一个哨兵当作 HWLAB Web 业务观察对象，也不能因为 HWLAB 业务 quick verify blocked 就把哨兵自身发布状态标成失败。

### 5.7 哨兵不可用结构化失败时序图

```mermaid
sequenceDiagram
  participant CI as CI/CD targetValidation
  participant Sen as Sentinel service
  participant Log as Structured closeout evidence

  CI->>Sen: validate or maintenance/stop
  Sen-->>CI: unavailable or first-install
  CI->>Log: missing service/config/health detail
  Log-->>CI: failed targetValidation and retry command
```

哨兵不可用、首次安装未完成或配置未就绪时，CI/CD 必须结构化失败并输出缺失项、恢复建议和可重试命令；不得自动切换到第二执行通道。人工排障仍可显式运行原 `web-probe observe` CLI，但该人工动作不属于 CI/CD targetValidation 的自动通过路径。

### 5.8 Dashboard 信息架构图

```mermaid
flowchart TD
  UI[Dashboard workbench] --> Overview[Overview<br/>health scheduler maintenance latest run]
  UI --> Runs[Runs history<br/>filter sort timeline]
  UI --> Findings[Findings analysis<br/>severity code window]
  UI --> Detail[Run detail]
  Detail --> TurnSummary[Turn summary<br/>multi-turn user message and final summary]
  Detail --> TraceFrame[Trace-frame viewer<br/>single turn/sample text snapshot]
  Detail --> Evidence[Evidence<br/>report SHA observer stateDir CLI command]
  Overview --> Runs
  Findings --> Runs
  Runs --> Detail
```

Dashboard 首屏必须先呈现当前值守判断，再允许 drill-down。用户打开 `monitor.pikapython.com` 后应能在首屏判断哨兵自身是否健康、最近 canary 是否 blocked、blocked 的 red/amber/info 组成和最近一次 report SHA。

### 5.9 Dashboard API 数据流图

```mermaid
flowchart LR
  Index[(SQLite index)] --> OverviewApi[/api/overview]
  Index --> RunsApi[/api/runs filters cursor]
  Index --> FindingsApi[/api/findings aggregate]
  Report[analysis/report.json] --> DetailApi[/api/runs/:id]
  Report --> ViewApi[/api/runs/:id/views]
  Artifacts[observe artifacts] --> ViewApi
  OverviewApi --> Dashboard
  RunsApi --> Dashboard
  FindingsApi --> Dashboard
  DetailApi --> Dashboard
  ViewApi --> Dashboard
```

Dashboard API 只能 reshape 已有 index、report 和 artifact view。筛选、分页、排序和聚合只改变读取方式，不新增采样、analyze、截图保存、Workbench API 读取或 trace 状态仲裁。

### 5.10 Dashboard trace drill-down 时序图

```mermaid
sequenceDiagram
  participant U as User
  participant D as Dashboard
  participant API as Sentinel API
  participant R as report/index/artifact view
  participant CLI as sentinel report / observe collect

  U->>D: open latest blocked run
  D->>API: run detail and turn-summary
  API->>R: read bounded report view
  R-->>D: turns, findings, report SHA
  U->>D: select turn/trace/sample
  D->>API: trace-frame view
  API->>R: render existing frame text
  R-->>D: trace rows and Final Response block
  CLI-->>U: same facts available through CLI trace-frame
```

Trace drill-down 必须保持两层阅读：第一层是多 turn 摘要，第二层是选中 turn/trace/sample 后的文字版 trace-frame。`Final Response` 在第二层固定成块展示；空内容显示 `(空内容)`，有内容按 redaction 策略展示摘要、字节数或允许展示的正文。

### 5.11 P8 quick verify 控制链路图

```mermaid
sequenceDiagram
  participant Val as sentinel validate
  participant Sen as Sentinel service
  participant Obs as observe runner
  participant Ctrl as control queue
  participant Web as HWLAB Workbench
  participant Ana as observe analyze
  participant Rep as report/dashboard

  Val->>Sen: /api/health through k3s Service DNS
  Val->>Obs: observe start
  Val->>Ctrl: command newSession
  Ctrl->>Web: create Workbench session
  Val->>Ctrl: command selectProvider/sendPrompt
  Ctrl->>Web: submit business turn
  Val->>Ana: observe analyze existing artifact
  Ana->>Rep: report SHA, findings, turn-summary, trace-frame
```

Quick verify 的通过条件必须覆盖控制命令、业务 turn 和 analyze/report 三段。`monitor.pikapython.com` root/CSS/JS 200 只证明公开 dashboard 外壳可读，不得抵消 `newSession`、`sendPrompt`、trace rows 或 final response 缺失。

### 5.12 P8 故障分类数据流图

```mermaid
flowchart LR
  Validate[sentinel validate] --> Shell[service/public dashboard health]
  Validate --> Control[observe command health]
  Validate --> Business[business turn health]
  Validate --> Runtime[runtime/browser health]
  Shell --> Result[validation result]
  Control --> Result
  Business --> Result
  Runtime --> Result
  Control --> NoTurn[quick-verify-no-business-turn]
  Business --> Trace[turn-summary and trace-frame]
  Runtime --> Timeout[timeout/readiness/session/api subtype]
```

分类必须先按 service/public-dashboard、control command、business turn、runtime/browser 分仓，再给可行动下一步。`browser-timeout` 不得默认归为浏览器安装或 Playwright 环境问题；它至少要被解释为页面导航、auth/login、Workbench readiness、session create、message submit、trace projection 或浏览器环境中的一个可复核子类。

### 5.13 P8 中文运维视图时序图

```mermaid
sequenceDiagram
  participant U as 用户
  participant D as 中文运维页面
  participant API as dashboard API
  participant CLI as CLI drill-down

  U->>D: 打开 monitor.pikapython.com
  D->>API: overview, runs, findings
  API-->>D: 服务健康、公开入口、最近业务验证、阻塞分类
  U->>D: 选择 blocked run/finding
  D-->>U: 中文解释、证据、CLI 对照命令、下一步动作
  U->>CLI: sentinel report / observe collect
  CLI-->>U: 同一 run/observer/report SHA 的文字 trace 证据
```

中文运维页面必须默认展示中文状态、中文说明和中文下一步，同时保留原始 run id、observer id、finding code、report SHA 和 CLI 命令，便于 issue/PR 证据对照。

## 6. 原子需求

### 6.1 OPS-SENTINEL-REQ-001 非分叉 wrapper 边界

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-001 | Wrapper边界 | PJ2026-0106050801 Wrapper边界 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Web工作台](PJ2026-010401-web-workbench.md) |

Web哨兵必须只编排现有顶层 `web-probe observe start/status/command/collect/analyze` 命令语义。常驻服务可以把这些 verb 包成稳定 adapter，但底层采样器、control queue、artifact schema、collect 渲染和 offline analyzer 必须与人工 CLI 共享同一实现或同一生成物。

旧 `hwlab nodes web-probe` 路径不得作为 alias、delegate 或第二执行路径继续运行；它只能 fail-fast 输出迁移说明并指向顶层 `web-probe`。常驻服务、人工 CLI、CI/CD targetValidation 和后续 YAML 示例都必须指向同一顶层入口。

实现不得新增第二套 Playwright runner、DOM sampler、network sampler、control command 协议、JSONL artifact schema、offline analyzer、finding classifier 或 Workbench 状态机。若服务化需要能力增强，必须先补到现有 `web-probe observe` 命令面，再由哨兵调用。

人工 CLI 是排障和原入口验收的一等入口；哨兵是调度入口。两者对同一 stateDir、同一 report 和同一 trace-frame 的解释必须一致。

### 6.2 OPS-SENTINEL-REQ-002 YAML-first 配置引用

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-002 | YAML配置 | PJ2026-0106050802 YAML配置 | [YAML运维](PJ2026-010603-yaml-first-ops.md)、[公开入口](PJ2026-010604-public-entry.md)、[源码同步](PJ2026-010602-source-sync.md) |

Web哨兵 legacy 单实例配置可通过 node/lane root YAML 的 `observability.webProbe.sentinel.enabled/configRefs` 进入；多实例配置必须通过 `observability.webProbe.sentinels[]` registry 进入。registry 项只能声明 `id`、`enabled` 和 `configRef`，再由 sentinel 管理 YAML 引用 runtime、workflow/scenario、promptSet、reportView、publicExposure、CI/CD 和 Secret owning YAML。root YAML 不得承载所有 runtime/scenario/report/Secret 数值，也不得生成合并后的超级配置作为第二 source of truth。

parser 只负责解析 `path/to/file.yaml#object.path` 或规格确认的等价引用，校验文件存在、路径存在、字段形状、类型、枚举键名、必填字段和重复事实冲突。registry id 与 sentinel 管理 YAML 内的 id 必须一致；多实例 registry 下的非 config 操作必须显式选择 `--sentinel <id>`，避免误操作默认实例。缺失字段应报告 YAML path 和下一步 drill-down；不得用代码默认值补 namespace、image、cadence、timeout、threshold、profile、Secret、public URL、report view 或 retention。

`sentinel plan/status` 必须输出 redacted 配置引用图：无 `--sentinel` 且存在多个实例时输出 registry 表和逐实例 drill-down；指定实例时输出该实例每个 ref 的文件、path、presence、摘要 hash、缺失字段、冲突字段和下一步命令。默认输出不得 dump 完整展开 YAML、Secret 值、prompt 原文或 provider payload。

### 6.3 OPS-SENTINEL-REQ-003 常驻服务和 artifact 索引

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-003 | 常驻服务 | PJ2026-0106050803 常驻服务 | [发布流水](PJ2026-010601-controlled-release.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |

Web哨兵服务应以 TypeScript/Node.js 实现，默认单 Pod 单副本。服务负责 scheduler、scenario runner、PVC/SQLite index、health、metrics、maintenance API 和 dashboard 静态资源；它不得直接写第二套 DOM 采样、网络采样、截图、Workbench 读取逻辑或 finding 分类。

PVC 保存 SQLite index 和原始 `.state/web-observe` artifact。SQLite 只索引 run、scenario、finding、report hash、artifact 摘要、maintenance 状态和分页游标；它不得替代 JSONL/report 事实源，不参与 Workbench lifecycle、trace 顺序、final response 或业务状态仲裁。

`/api/health` 必须覆盖 scheduler loop、SQLite/PVC 可写、最近 heartbeat、analyze 可执行性和必要配置装载。SQLite/PVC 不可写、scheduler 停摆、最近 heartbeat 超时或 analyzer 失败时，health 应非健康。`/metrics` 至少暴露 run 成功率、最近 finding 数、采样延迟、active observer 数和 maintenance 状态。

Pod 重建后应从 PVC 恢复 index 与最近 artifact 摘要；进行中 run 可以标记 `interrupted` 并重新调度，不能静默假绿。

### 6.4 OPS-SENTINEL-REQ-004 报告视图和 dashboard

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-004 | 报告视图 | PJ2026-0106050804 报告视图 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |

Web哨兵的 `sentinel report` 和 dashboard 必须按 YAML report views 渐进展示同一 observe/analyze artifact：run overview、turn-summary、findings、trace-frame/sample drill-down 和显式 raw artifact 下载。默认视图不得 dump JSONL，也不得展示 prompt 原文、完整 assistant 正文、cookie、token、API key、provider payload 或完整 stdout/stderr。

`sentinel report --latest|--run <runId> --view summary|turn-summary|findings|trace-frame` 的默认分页、最大分页、可用 view、redaction 和 raw artifact 开关来自 owning YAML。完整 artifact 读取必须显式 `--raw` 或 `--artifact analysis/report.md|analysis/report.json`。

自动 finding 必须能被 CLI trace 视图复核。若 analyzer finding 与 `trace-frame` 冲突，应以 `trace-frame` 暴露的有序 turn/message/part/final response 事实作为人工判定基准，并把 analyzer 精度问题登记到工具侧；dashboard 不得用聚合计数覆盖 CLI trace-frame。

Dashboard report API 必须提供 bounded、redacted、可分页的 view contract。`/api/overview` 提供 health、scheduler、maintenance、latest run、severity counts 和 freshness；`/api/runs` 提供 scenario/status/severity/time/search 过滤与 cursor 分页；`/api/runs/:id` 提供 run detail、report refs、artifact refs 和 summary counts；`/api/findings` 提供 severity/code/scenario/window 聚合；`/api/runs/:id/views` 提供 summary、turn-summary、findings 和 trace-frame 的只读渲染。所有响应都必须能追溯到 run id、observer id、stateDir 和 report SHA。

P8 起，quick verify 如果没有产生 sendPrompt 业务 turn、有效 session、trace rows 或 final response，必须记录独立 red blocker `quick-verify-no-business-turn`。该 blocker 属于 quick verify 控制层事实，不得由 dashboard 前端临时推断；dashboard 和 `sentinel report --view findings` 只能展示已记录的同一 finding。

P8 恢复判定必须把 Workbench 业务失败继续 drill-down 到运行面依赖。当 trace-frame 或 Final Response 暴露 `hwlab-cloud-api request handling failed`、PostgreSQL `53300`、`too many clients already` 或等价 DB 连接槽耗尽证据时，quick verify 不能收口为前端展示缺陷；必须检查 PK01/PostgreSQL `max_connections`、各服务连接池、CrashLoop 探针风暴和当前 `pg_stat_activity`，并通过 YAML source of truth 收敛容量或池化参数。

### 6.5 OPS-SENTINEL-REQ-005 CI/CD、GitOps 和 maintenance

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-005 | 发布集成 | PJ2026-0106050805 发布集成 | [发布流水](PJ2026-010601-controlled-release.md)、[源码同步](PJ2026-010602-source-sync.md)、[公开入口](PJ2026-010604-public-entry.md) |

Web哨兵自身必须纳入受控且独立的 sentinel control-plane：source 来自 UniDesk `master`，镜像、GitOps path、Argo Application、publicExposure 和 targetValidation 由 Web 哨兵 owning YAML 声明。D601/v03 当前可通过 `web-probe sentinel image|control-plane` 的独立 publish Job 实现构建、推送、GitOps 写回和 Argo 收敛；后续也可以切换到 Tekton Pipeline，但 builder 类型必须来自 YAML，不得依赖 operator 本地 dirty worktree。

哨兵 rollout 与 HWLAB runtime rollout 不是同一个滚动单元。哨兵 dashboard/API/服务代码变更应通过 Web 哨兵独立 control-plane 滚动；HWLAB runtime 发布流水只调用当前已部署哨兵的 `maintenance/start`、`maintenance/stop` 和 quick verify 作为恢复判定。哨兵 control-plane 的顶层状态只表达哨兵自身 source、镜像、GitOps、Argo、runtime、metrics 和 dashboard 是否发布成功；HWLAB quick verify 必须作为独立 `targetValidation` 状态、warning 和 report 证据输出。哨兵 validate、maintenance 和 quick verify 控制路径必须优先走 k3s 内部 Service DNS，不绕 `monitor.pikapython.com` 公网入口。

哨兵镜像构建应使用 YAML 声明的 tools image、base image、registry、egress proxy 和 env-reuse 配方。Node/Bun/Playwright/Chromium 依赖不得在 runtime Pod 中临时下载。Secret 与 env 复用只走 sourceRef/keyMapping；日志、status、dashboard 和 issue closeout 只输出 object/key/presence/fingerprint/digest。

HWLAB runtime 发布 Pipeline 应在 Argo sync 前调用当前哨兵 `maintenance/start`，进入观察不告警模式；sync 完成且业务 Deployment Ready 后调用 `maintenance/stop`，触发同一 observe CLI quick verify 和 analyze。targetValidation 不能只因 Argo `Synced/Healthy` 通过而绿；还必须包含 quick verify 结果、analysis report SHA、finding 摘要、public origin、scenario id 和 observer/run id。

哨兵服务不可用、首次安装未完成或配置未就绪时，CI/CD 必须结构化失败并输出缺失项、恢复建议和可重试命令；不得自动回退到原纯客户端 CLI、裸 Playwright、私有 API、read-side repair、reload 循环或 session repair 形成第二执行路径。人工排障可以显式运行原 `web-probe observe start/status/command/collect/analyze`，但不能被 targetValidation 当作自动通过证据。

`web-probe sentinel control-plane trigger-current --confirm --wait` 只等待 source mirror、publish、flush、publicExposure、Argo 和 runtime observed 收敛；CI/CD confirm-wait 超过 YAML `confirmWait.maxSeconds`（当前 120s）时必须输出 warning，并先优化等待阶段耗时，不得继续把长业务验证塞在部署同步路径里死等。`sentinel validate --quick-verify --confirm --wait` 和 maintenance stop quick verify 才执行 targetValidation 业务验证；业务 quick verify 可通过 YAML `targetValidation.maxSeconds` 放宽到 300s。计时超限本身只作为非阻塞告警；只有真正影响 Code Agent 多轮业务链路、submit/command 执行、trace/final 可见性或 session 连续性的失败才构成 targetValidation blocker。不得通过减少业务轮次、吞掉 submit 失败、fallback 到第二执行路径或读侧 repair 来消除红灯。

### 6.6 OPS-SENTINEL-REQ-006 dsflash-go 十轮 canary

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-006 | Canary验收 | PJ2026-0106050806 Canary验收 | [Agent编排](PJ2026-0102-agent-orchestration.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[API契约](PJ2026-010403-api-contract.md) |

第一条生产 canary 固定为 `workbench-dsflash-go-tool-call-10x`。所有运行参数都必须来自 configRefs 解析出的 owning YAML，至少包括 node/lane、public origin、targetPath、cadenceSeconds、sampleIntervalMs、screenshotIntervalMs、maxRunSeconds、maxConcurrentRuns、sessionPolicy、backendProfile、promptSetRef、rounds、requireToolCalls、report view、pagination、analyze thresholds、retention、publicExposure 和 maintenance 策略。

调度器每隔 YAML 声明 cadence 创建新的 HWLAB Workbench session；每个 run 通过同一 `web-probe observe start` 启动采样，并通过同一 `observe command` 下发 `newSession`、provider 选择和十轮 prompt。prompt 原文必须由 prompt sourceRef 管理，报告只展示 prompt id/hash/bytes 和轮次编号。

第一 canary 必须在十轮连续 prompt 中插入 YAML 声明的 `sessionInvarianceChecks`。固定检查点为第 1 轮后、第 5 轮后和第 10 轮后：第 1/5 轮后执行显式 `refreshCurrentSession`、`switchAwayAndBack` 和 `assertSessionInvariant` control command；第 10 轮后只刷新当前 canary session 并断言最终回读。切换窗口必须进入 `control.jsonl`，不得由哨兵服务私自驱动第二套 Playwright，也不得靠刷新、切 session 或 result polling 修复 Workbench 投影。

刷新/切换检查只检测同一 canary session 的消息/trace/final 投影顺序。受控切走和切回窗口内的 `session-route-changed` / `active-session-changed` 不构成业务异常；切回后仍存在 route/active mismatch、trace 丢失、final 缺失或 command failure 时沿用既有 blocker 规则。若同一 session 可见消息出现多个 user message cards 连续展示，且这些 user cards 之间缺少 assistant/agent/code-agent terminal 或 response card，`observe analyze` 必须产生 `workbench-message-order-user-clustered-after-navigation`，severity=`amber`，blocking=`false`，并记录 afterRound、canarySessionId、routeSessionId、activeSessionId、连续 user 数量、sentinel marker 范围、sample seq、traceId 列表、pageRole/pageId 和 redacted message order 摘要。

`observe analyze` 对 Workbench read-model 类问题必须输出稳定 rootCause code，便于 issue closeout、OTel drill-down 和 dashboard 过滤：消息 role cluster 使用 `session_message_role_clustered`；trace event page 404 使用 `trace_events_paging_contract_mismatch`；projection/read-model 长期落后使用 `projection_read_model_stale`；session rail fallback title/preview 使用 `session_title_fallback_from_facts`。这些 finding 必须保持脱敏，只输出 opaque id、hash、seq、count、ratio、traceId/sessionId 前缀或红acted 摘要，不输出 Secret、完整 prompt 或 provider payload。

每一轮任务都必须需要工具调用。验收报告要证明十轮在同一 session 内完成，记录每轮 traceId、terminal status、tool-call evidence/count、耗时、慢 API、network/console/requestfailed finding、trace 顺序异常、terminal-not-last、session mismatch 和 final-response flicker。

`dsflash-go` 是 AgentRun backend profile。实现必须验证 profile-scoped SecretRef、config 和 `model-catalog.json` presence/fingerprint；缺失时结构化失败，不允许 fallback 到 `codex`、`deepseek`、`minimax-m3` 或其他 profile。

24 小时 dry-run 应在至少一个 HWLAB node/lane 完成，按 YAML cadence 形成不少于一天的 run 序列，并回写 observer/run id、stateDir/PVC 摘要、analysis report SHA、finding 摘要、截图/artifact 计数、Prometheus metrics 和 public dashboard HTTPS 验证。

### 6.7 OPS-SENTINEL-REQ-007 安全、隔离和公开入口

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-007 | 安全隔离 | PJ2026-0106050807 安全隔离 | [用户管理](PJ2026-0105-user-management.md)、[公开入口](PJ2026-010604-public-entry.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md) |

Web哨兵运行 namespace 与业务 runtime namespace 分离，具体 namespace、ServiceAccount、PVC、Service、NetworkPolicy 和 resource request/limit 由 YAML 声明。Service 默认 ClusterIP；不得用 NodePort、LoadBalancer、hostNetwork、hostPort 或手工 Ingress 暴露 dashboard。

`monitor.pikapython.com` HTTPS 暴露必须走 YAML publicExposure，使用共享 PK01 Caddy + FRP managed-block helper 渲染。实现不得手工编辑 Caddyfile，不得替换其他 UniDesk managed block，不得复制 Caddy/FRP writer。public exposure closeout 必须验证 DNS、TLS、HTTPS、认证/维护 token、edge 和 ClusterIP upstream。

Secret 只通过 sourceRef/targetKey 下发，CLI、服务日志、dashboard 和 issue evidence 只能输出 sourceRef、object、key、presence、fingerprint、hash、字节数和 redacted 摘要。prompt 原文、assistant 长正文、provider payload、cookie、token、API key、完整 DSN 和 stdout/stderr 不进入默认输出或 dashboard。

NetworkPolicy 默认只允许 DNS、YAML 声明 public origin/必要 service endpoint、Prometheus scrape 来源和管理入口。任何扩大 egress/ingress 的变更必须先进入 owning YAML 和 plan 输出。

### 6.8 OPS-SENTINEL-REQ-008 SPEC-first 与代码引用

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-008 | 代码引用 | PJ2026-0106050808 代码引用 | [规格治理](spec-governance.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md) |

Web哨兵实现必须先引用本规格，再进入代码变更。新增或修改的 CLI、adapter、service、scheduler、metrics、manifest renderer、public exposure helper、CI/CD helper 和 report renderer 源码文件头部必须标注 `SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-25-p0-web-probe-sentinel`，并用一句话说明文件职责。

P7 dashboard 增强范围内新增或修改的 dashboard API、frontend assets、renderer、format composable、auto refresh、run/detail/finding/trace-frame viewer 源码文件头部必须标注 `SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-26-p7-web-probe-sentinel-dashboard`，或在既有 Web哨兵源码头部追加该实现引用版本。纯 YAML/config、锁文件、构建产物和无法承载注释头的静态资源可例外，但对应生成器、serving 入口或 manifest renderer 必须能追溯到该版本。

P10/P11 monitor-web 范围内新增或修改的 Vue/TypeScript/Vite 前端、typed API client、聚合 API、runner discovery、dashboard verify/screenshot、CI/CD renderer、GitOps/publicExposure helper 和 env reuse 规划代码必须标注 `SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-27-p11-monitor-web-observability-dashboard`。旧 `scripts/assets/web-probe-sentinel-dashboard/dashboard.js` 只能标注迁移前短修或兼容验证用途，不得作为 P11 新观察面板能力的主要承载面。

实现文件不得只写 issue 编号、`latest`、`current` 或“按最新方案”作为规格引用。自动生成文件、第三方 vendored 文件、纯 YAML/config、锁文件和无法承载注释头的二进制产物不要求加源码头部，但对应生成器、渲染器、owning YAML 或 CLI 入口必须能追溯到本 SPEC。

后续 P1-P6 阶段如果改变稳定需求、观察对象、数据流、接口、部署边界或验收口径，应先更新本规格和上级 [PJ2026-010605 运维监控](PJ2026-010605-observability-monitoring.md)，再更新执行 issue。

### 6.9 OPS-SENTINEL-REQ-009 Dashboard 值守和分析工作台

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-009 | Dashboard工作台 | PJ2026-0106050809 Dashboard工作台 | [Workbench性能](PJ2026-01060505-workbench-performance.md)、[Web工作台](PJ2026-010401-web-workbench.md) |

Dashboard 必须是值守和分析工作台，而不是 raw JSON 或单列表格。首屏至少呈现 overall status、node/lane/public origin、config readiness、scheduler heartbeat age、maintenance 状态、latest run、120s targetValidation budget、severity counts 和最新 report SHA。超过 120s 的 quick verify 或 canary 仍应保持 warning/red，不得通过调大预算、减少轮数或 fallback 视图变绿。

Runs history 必须支持 scenario、status、severity、时间窗口、maintenance、observer id、run id 和文本搜索；排序至少覆盖 updated time、created time、finding count 和 severity。Run timeline 应稳定展示最近窗口状态，帮助用户判断 blocked 是否连续、同一 finding 是否反复出现。

Findings analysis 必须把 finding 升级为可点击分析对象：按 severity 分组，按 code/scenario/window 聚合，展示 count、最近出现、关联 run 和 latest report SHA。点击 finding 应能过滤 runs 或打开关联 run detail，不能只显示计数。

Run detail 必须展示 summary、findings、turn-summary、trace-frame 入口、artifact/report refs、CLI 对照命令和 valuesRedacted 标记。Trace 阅读必须分两层：多 turn 摘要用于选择 turn，单 turn trace-frame viewer 用于阅读具体采样帧并固定显示 `Final Response` 区块。

Dashboard 前端架构应借鉴 Sub2API 监控面板的分层方式：typed API client、format composable、auto refresh composable、Overview、Run table、Finding groups、Timeline、Run detail、Trace-frame viewer、loading/empty/error 状态和深链 query。实现不得继续把完整 UI、API shaping、DB 查询、CSS 和 artifact 解析堆进单个服务文件；超过 3000 行或职责混杂的文件必须按职责拆分。

Dashboard 自动刷新只能读取 bounded API，不得发送 `observe command`、不启动新采样、不重新 analyze、不保存额外截图。页面 hidden、loading 或上一次请求未完成时应暂停或跳过刷新，避免监控 UI 自身制造额外压力。

P11 起，长期权威观察面板是 Vue `monitor-web`，不是 runner 内置 vanilla dashboard。迁移前 runner dashboard 可以继续承担单哨兵兼容、短修和回归对照，但趋势曲线、固定视口三栏、运行时间线、多哨兵聚合、cadence freshness 和 root cause 默认可见性必须在 `monitor-web` 中设计和验收。

P8 中文运维页面必须以中文为默认用户可见语言：主标题、状态、筛选、运行历史、finding 分组、run detail、trace-frame、Final Response、空态、错误态、自动刷新和下一步动作均使用中文。原始英文 code、status 枚举、CLI 命令和 report SHA 可作为机器对照保留，但不得要求用户阅读英文 finding 才能判断 HWLAB 是否可用、卡在哪一层、下一步运行什么命令。

### 6.10 OPS-SENTINEL-REQ-010 多实例巡检与账号切换链路

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-010 | 多实例与账号切换 | PJ2026-0106050810 多实例与账号切换 | [YAML运维](PJ2026-010603-yaml-first-ops.md)、[用户管理](PJ2026-0105-user-management.md)、[公开入口](PJ2026-010604-public-entry.md) |

Web 哨兵多实例必须以 node/lane root YAML 的 `observability.webProbe.sentinels[]` 为唯一 registry。每个 registry 项必须通过 `configRef` 指向独立 sentinel 管理 YAML，管理 YAML 再声明 runtime、workflow/scenario、promptSet、reportViews、publicExposure、cicd 和 secrets configRefs。legacy `observability.webProbe.sentinel` 只能作为单实例兼容入口；当同一 node/lane 存在多个 sentinel 时，除 `plan/status` registry 总览外，image、control-plane、validate、maintenance、report 和服务启动都必须显式携带 `--sentinel <id>`。

每个 sentinel 必须拥有独立的 Deployment、ServiceAccount、Service、PVC、SQLite path、GitOps path、Argo Application、FRP Secret/Deployment、metrics label、report index namespace 和 dashboard/report route label。不同 sentinel 可以共享同一 public hostname，但必须通过 YAML `routePrefix` 或等价 publicExposure 声明区分路径；不得共享同一个 PVC/SQLite 后再用 scenario id 伪装实例隔离。

`workbench-dsflash-go-tool-call-10x` 是保留的生产 canary，迁移到多实例 registry 后其 observe/analyze、report view、dashboard root 和 targetValidation 语义不得回退。迁移 closeout 必须证明旧实例 `sentinel plan --sentinel workbench-dsflash-go-tool-call-10x` 仍能解析原 runtime/scenario/prompt/report/publicExposure/cicd/secrets 引用。

`workbench-auth-session-switch-2users` 是账号切换链路哨兵。账号 A/B 的用户名、密码或 token 只能来自 Secret sourceRef 和 targetKey；CLI、服务日志、dashboard、report 和 issue evidence 只能展示 account id、sourcePurpose、presence、fingerprint 或 redacted 摘要。workflow 必须通过同一 `web-probe observe command` 控制队列支持 `loginAccount`、`logout`、`listSessions` 和 `switchSessions` 命令；submit 或命令失败必须作为结构化失败解决和上报，不能只写到备注里。

账号切换 report view 至少要给出账号 A/B login/logout 成败、session 列表可见性、切换前后 active session/account id、trace/final 可见性、blocked finding 和同一 observer/run/report SHA。`auth-session-switch-summary` 视图只读取已有 artifact/report/index，不重新访问 Workbench、不保存第二套截图、不打印账号凭据。

多实例 public exposure 复测必须通过受控 `web-probe screenshot` 或沉淀后的 command 远程截图能力完成，并把 PNG 保存到调用者 `/tmp` 下用于人工布局分析。修复 dashboard 布局问题后，复测截图必须覆盖 root dashboard 和至少一个 sentinel route prefix。

### 6.11 OPS-SENTINEL-REQ-011 Monitor Web 聚合

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-011 | Monitor Web 聚合 | PJ2026-0106050811 Monitor Web 聚合 | [公开入口](PJ2026-010604-public-entry.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md)、Dashboard工作台、多实例与账号切换 |

P10 起，Web 哨兵运行面必须区分 `sentinel-runner` 与 `monitor-web`。`sentinel-runner` 继续以每个 sentinel id 一套 Deployment、Service、PVC、SQLite index、scheduler、observe wrapper、report API、health 和 metrics 的形态存在；它只负责采样、分析、索引和提供单哨兵渐进读取 API。`monitor-web` 是独立的展示和聚合层，负责 `monitor.pikapython.com` root、所有 enabled sentinel 的 registry 总览、聚合 overview/runs/findings、单哨兵 detail route、受控截图/验证入口和人类值守信息架构。runner 不得因为聚合需求而回退到共享 Pod、共享 PVC 或共享 SQLite。

`monitor-web` 配置必须是 YAML-first。node/lane、namespace、Deployment、Service、publicExposure、runner discovery label selector、read timeout、聚合 API、静态资源托管方式、RBAC、NetworkPolicy 和 Secret sourceRef 都必须来自 owning YAML 或 configRef。root `observability.webProbe.sentinels[]` 仍是 enabled sentinel registry；`monitor-web` 可以读取该 registry 与 Kubernetes Service/EndpointSlice discovery 结果做一致性校验，但不得把发现结果写回成第二 source of truth。

Runner discovery 优先使用 Kubernetes 原生对象：runner Service/Pod 必须带 `unidesk.ai/web-probe-sentinel-id`、node、lane、workspace 和 component label；`monitor-web` 使用 Service list/watch 或 EndpointSlice list/watch 按 label selector 发现 ClusterIP runner endpoint。Prometheus/ServiceMonitor 只用于低基数 metrics scrape，不承载 report drill-down，也不替代 runner HTTP API。runner Service 默认 ClusterIP；公网只暴露 `monitor-web`，不逐个暴露 runner。

`monitor-web` 前端目标技术栈为 Vue 3 + TypeScript + Vite，并与 HWLAB Cloud Web 的组件拆分、typed API client、状态管理、加载/空态/错误态、Markdown/代码块渲染和样式约定对齐。旧 `scripts/assets/web-probe-sentinel-dashboard/dashboard.js` vanilla `innerHTML` 实现只允许作为迁移前的短修和对照，不再作为 monitor-web 新能力的长期承载面。迁移前的短修仍必须保留 P8/P9 三栏、高信息密度、中文运维页面、渐进披露和 trace-frame 入口。

P10 dashboard 受控验收必须沉淀为 CLI 入口。`web-probe sentinel dashboard verify|screenshot` 或等价命令必须从 selected sentinel 的 YAML `publicExposure.publicBaseUrl` 解析 URL，通过远程浏览器执行 JS、采集 pageerror/console/requestfailed/DOM 行数/布局溢出和截图 SHA。`validate` 中的 public dashboard 200 只证明 HTML/CSS/JS 静态资源可达，不能替代浏览器渲染验收。

`monitor.pikapython.com` root 的目标首屏必须展示所有 enabled sentinels 的 latest status、latest run、red/amber/info 摘要、freshness、runner degraded 状态和 drill-down 链接；`/sentinels/<id>` 必须展示单哨兵 runs/findings/detail/trace-frame。删除或重启一个 runner 只能让对应 sentinel 显示 degraded，不得让 root 变成空白或阻断其他 runner 数据。聚合 API 必须 bounded、分页、redacted，不打印 Secret、prompt 原文、provider payload、cookie、完整 stdout/stderr 或完整 report。

### 6.12 OPS-SENTINEL-REQ-012 Monitor Web 观察面板与 CI/CD 治理

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-012 | Monitor Web 观察面板治理 | PJ2026-0106050812 Monitor Web 观察面板治理 | Monitor Web 聚合、Dashboard工作台、[源码同步](PJ2026-010602-source-sync.md)、[发布流水](PJ2026-010601-controlled-release.md) |

`monitor-web` 首屏信息架构必须把值守判断放在最前：顶部状态与全局操作之后，先显示哨兵入口，再在哨兵入口正下方展示运行趋势曲线。趋势曲线至少展示最近运行窗口内 red finding count、warning/amber finding count 和 total finding count；当前选中 run、maintenance window、缺失 report、stale run 和 runner degraded 必须有可见标记。

趋势曲线、运行时间线、runs 表、run detail 和 findings 必须共享同一选中 run 状态。用户 hover 或点击趋势点/时间线节点时，应看到 run id、updatedAt、status、red/warning/total、report SHA 短码和 rootCause 摘要；点击后必须更新深链 query 并联动三栏工作区。趋势数据首版可以从 bounded `/api/runs` 和 `/api/overview` 派生；若需要更长窗口，新增 `/api/trends` 或等价聚合 API 时仍必须 bounded、分页、redacted，并追溯到 run/report SHA。

桌面端 `monitor-web` 必须使用固定视口工作区，避免 document 级无限长页。左侧运行历史、中间运行详情、右侧发现分析应在同一 viewport 内独立上下滚动，并使用稳定高度、`min-height: 0`、可预测列宽和移动断点；运行时间线应靠近趋势区，允许横向滚动或紧凑显示，不得通过 flex wrap 把页面整体撑长。1366x768、1440x900 和 960x600 视口必须通过远程截图验证无关键文字重叠、按钮溢出、图表撑破或横向 overflow。

cadence freshness 必须成为 `monitor-web` 的一等状态。每个 sentinel 应显示 YAML expected cadence、scheduler heartbeat age、latest run age、latest analyzed report age、active run、planned/next run 和 stale 倍数。cadence stale 默认是非阻塞告警；只有 scheduler 停摆、run/report 长时间不产生、submit/command 失败、采样样本缺失、或 Code Agent 多轮业务链路不可继续时，才升级为 blocker。面板不得把 timing warning、terminal-boundary elapsed correction 或单纯超时预算告警伪装成业务 blocker。

P12 runner-served-bridge 形态下，sentinel runner Pod 可以只承载 API、PVC/SQLite index、health、metrics 和 dashboard 静态资源；若 Pod 内没有完整 repo 配置、`trans`、Chromium 或 observe 依赖，不得让 Pod 自行 SSH/回调宿主机触发巡检。周期巡检必须由受控宿主控制面调度器读取同一 YAML registry、scenario/workflow cadence、publicExposure 和 targetValidation timeout，按 stale 窗口触发现有 `web-probe sentinel validate --quick-verify --confirm --wait` 路径。该调度器只负责 due 判断、互斥锁、timeout、命令执行和 JSONL 事件日志，不实现第二套采样、analyze、finding 分类或 report 写入。

宿主控制面调度器必须由目标 node/lane 的 k3s CronJob/GitOps 或等价受控入口周期调用，默认 tick 间隔不得替代 YAML cadence；每次 tick 必须输出 sentinel id、cadence、latest run age、due、trigger status、latest run id 和下一步 drill-down。触发失败要区分业务 finding、命令 submit/control 失败、overview/API 不可达、lock-held 和 timeout；业务 finding 已产生新 run 时不得把 scheduler 本身标为 infra blocker。`monitor-web` 应继续把 stale run 作为非阻塞告警展示，但 run/report 持续不更新或 submit/control 失败必须能在面板和 CLI 中直接看到根因。

`monitor-web` 前端必须使用 Vue 3 + TypeScript + Vite，并与 HWLAB Cloud Web/Sub2API 运维图表的组件化方式对齐：typed API client、format composable、auto refresh composable、chart component、timeline component、run table、detail tabs、finding groups、loading/empty/error 状态和深链路由。图表库不是前置结论；可选 Chart.js、ECharts 或原生 SVG/canvas，但 SPEC/PR 必须说明包体、构建耗时、交互能力和维护成本取舍。

Vue `monitor-web` 的 CI/CD 必须和架构一起交付。YAML 必须声明 source、build context、Node/Bun/Vite 构建环境、env image、dependency cache、registry image、GitOps path、Argo Application、Service、publicExposure、runner discovery selector 和 screenshot 验收命令。CI 读源码必须优先走 node/lane 声明的 git mirror read URL；触发 PipelineRun 前做受控 pre-sync，GitOps promotion 后做受控 post-flush，并在 status/closeout 中输出 `pendingFlush`、`githubInSync`、source commit、GitOps revision 和 PipelineRun 名称。

Vue `monitor-web` 构建必须利用 env reuse、CI tools/env image、依赖缓存和镜像层缓存。未修改 runner/backend/API 时不得重建无关运行面；纯 SPEC、CLI、文档或无需 runtime 重建的提交应在 status 中呈现 `build=0 reuse=<service-count>` 或等价 reuse 证据。Vue `monitor-web` CI/CD 总耗时或单个 build TaskRun 超过两分钟时，必须先从 env reuse、依赖缓存、git mirror pre-sync、镜像层缓存和无关服务重建方向优化，再继续 UI 功能实现；不得死等长 PipelineRun 后只记录超时。

发布成功判据不能只看 legacy `dashboard.js` 静态资源 200。Vue `monitor-web` closeout 必须记录 Vite 产物内容 hash、asset 200/字节数/SHA、HTML 引用一致性、`/health`、root 聚合页 browser render、至少一个 `/sentinels/<id>` 详情页 render、远程 PNG localPath/SHA、DOM 摘要、overflow 结果、Argo/runtime/source/GitOps/git mirror alignment 和 runner degraded 降级行为。所有触发、rollout、status、git mirror sync/flush 和截图验收必须走 UniDesk 受控 CLI。

### 6.13 OPS-SENTINEL-REQ-013 D518 多 runner 强边界与 OTel 根因收敛

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-013 | D518 多 runner 强边界 | PJ2026-0106050813 D518 多 runner 强边界 | 多实例与账号切换、Monitor Web 聚合、OTel、AgentRun、YAML运维 |

本阶段执行 issue 为 [#1206](https://github.com/pikasTech/unidesk/issues/1206)，阶段子 issue 为 P0 [#1208](https://github.com/pikasTech/unidesk/issues/1208)、P1 [#1209](https://github.com/pikasTech/unidesk/issues/1209)、P2 [#1210](https://github.com/pikasTech/unidesk/issues/1210)、P3 [#1211](https://github.com/pikasTech/unidesk/issues/1211)、P4 [#1212](https://github.com/pikasTech/unidesk/issues/1212)、P5 [#1213](https://github.com/pikasTech/unidesk/issues/1213)、P6 [#1214](https://github.com/pikasTech/unidesk/issues/1214)、P7 [#1215](https://github.com/pikasTech/unidesk/issues/1215) 和 P8 [#1216](https://github.com/pikasTech/unidesk/issues/1216)。

D518/v03 不允许再以“多个 sentinel 配置入口共享一个 runner Deployment/Service/PVC/SQLite/FRP/Caddy owner”的形式上线。每个 sentinel 必须有独立 runtime configRef，至少独立声明 Deployment、Service、ServiceAccount、PVC、stateRoot、SQLite path、CronJob、FRP Deployment、FRP Secret、httpProxy name、remotePort、GitOps path 和 Argo Application。`observeWrapperRef` 不得使用 `sentinels[0]` 这类位置索引；必须由 selected sentinel id 解引用或用等价稳定 id 绑定。

runner API 的边界必须是硬约束。`/api/overview`、`/api/runs`、`/api/findings`、`/api/runs/:id` 和 `/api/report` 只能返回当前 runner `sentinelId`、node、lane 下的数据；SQLite schema 至少包含 `sentinelId/scenarioId/observerId/runId`，并对 runs/findings 建立 sentinel 维度索引。route sentinelId 与服务实例 sentinelId 不一致时，API 必须返回结构化 `sentinel-route-mismatch` blocker，不允许 fallback 到其他 sentinel 的 latest run，也不允许前端过滤后继续展示。

状态语义必须区分 latest selected run 与 historical trend。latest run 的 `blocked/failed/error/timeout` 可以驱动当前状态为 blocker；历史趋势里的 red/error 样本只能作为趋势或历史风险展示，不能把一个已选 latest run 误标为当前阻塞。timing budget 超过 YAML `targetValidation.maxSeconds` 但已采集到 durable completed business turn 时，默认是非阻塞 timing warning；只有 submit/control 失败、样本缺失、报告未生成或 Code Agent 多轮业务链路不可继续时才升级为 blocker。

dashboard verify/screenshot 必须断言 selected sentinel 的 route 和 API 返回一致：远程浏览器脚本必须检查 DOM bootstrap `data-sentinel-id`、`/api/overview.sentinelId`、`/api/runs.sentinelId`、runs rows 的 `sentinelId` 和 public URL routePrefix。任何 dsflash route 返回 fake-echo 数据、fake-echo route 返回空 body 或 root route 绑定单 runner 的情况都必须失败并给出有界证据。

OTel 根因契约必须与应用内 report/index 分工清楚。sentinel report/index 负责 latest、history、finding、artifact、timeline、availability 和 runner heartbeat；OTel/Tempo 负责跨服务根因链路。D518 `diagnose-code-agent` 的 AgentRun namespace/lane 必须从 `config/hwlab-node-lanes.yaml` 解析到实际 `agentrun-v02`，不得硬编码 `agentrun-v01`。HWLAB cloud-api、AgentRun manager 和 AgentRun runner 的 span 必须能通过 trace context 串联；缺失任一段时标为 instrumentation blocker 或 instrumentation gap，不得静默跳过。

## 7. 过程控制

Web哨兵架构执行 issue 为 [#883](https://github.com/pikasTech/unidesk/issues/883)。阶段跟踪 issue 为 P0 [#885](https://github.com/pikasTech/unidesk/issues/885)、P1 [#886](https://github.com/pikasTech/unidesk/issues/886)、P2 [#887](https://github.com/pikasTech/unidesk/issues/887)、P3 [#888](https://github.com/pikasTech/unidesk/issues/888)、P4 [#889](https://github.com/pikasTech/unidesk/issues/889)、P5 [#890](https://github.com/pikasTech/unidesk/issues/890) 和 P6 [#891](https://github.com/pikasTech/unidesk/issues/891)。

P0 未完成前，不得推进 CLI wrapper、服务实现、YAML schema、CI/CD、dashboard 或部署代码阶段。P1-P6 的 PR closeout 必须回写：使用的 SPEC 编号和实现引用版本、触达的源码文件头部标注情况、owning YAML/configRef 变更、原 CLI 入口兼容性、验证命令、public origin 或运行面证据，以及是否需要继续修订本规格。

Dashboard 增强执行 issue 为 [#935](https://github.com/pikasTech/unidesk/issues/935)。P7 阶段跟踪 issue 为 P0 [#938](https://github.com/pikasTech/unidesk/issues/938)、P1 [#940](https://github.com/pikasTech/unidesk/issues/940)、P2 [#941](https://github.com/pikasTech/unidesk/issues/941)、P3 [#939](https://github.com/pikasTech/unidesk/issues/939)、P4 [#943](https://github.com/pikasTech/unidesk/issues/943)、P5 [#942](https://github.com/pikasTech/unidesk/issues/942) 和 P6 [#944](https://github.com/pikasTech/unidesk/issues/944)。P7 实现 PR closeout 必须回写 dashboard API contract、frontend 分层、trace-frame 对照、redaction、`monitor.pikapython.com` 验证和哨兵独立 CI/CD 状态。

P7 P6 收口必须区分 public dashboard validation 与 targetValidation quick verify：`monitor.pikapython.com` root/CSS/JS 200 只证明公开入口和静态 dashboard 资源可用；quick verify 的 `observe command`、采样样本、analyze report 和 red finding 仍是业务恢复判定的一部分。若 quick verify 因 `observe-command-newSession-failed`、`no-samples` 或等价采样器控制失败而 blocked，P6 issue 必须保持未关闭或显式拆出后续 blocker，不得只凭 public dashboard 200 关闭。

P8 哨兵恢复执行 issue 为 [#971](https://github.com/pikasTech/unidesk/issues/971)。P8 closeout 必须回写：SPEC P8 引用、120s warning 证据、`quick-verify-no-business-turn` 或等价业务触达证据、`browser-timeout` 分类修正、中文运维页面验证、`monitor.pikapython.com` 公网入口验证、k3s 内部 Service DNS quick verify 路径、D601/v03 用户入口 smoke 结果，以及仍未解除的真实业务 blocker 是否已单独拆出。

P8-P8 起，targetValidation 的 availability blocker 与 Workbench timing 架构治理必须分层。若同一 trace 在 terminal 前最后一帧仍为 running，随后 terminal commit 的 sealed `durationMs` 把可见 `totalElapsed` 小幅校正到更短值，且 drop 不超过 YAML `turnTimingSampleSlackSeconds`、final response 与完成行均已可见，则该现象作为 terminal-boundary timing correction 证据保留，不生成 `turn-timing-total-elapsed-decrease` red blocker。归零、running/running 下降、terminal 后增长、完成耗时与卡片耗时超出 slack、trace 乱序和完成行非最后仍保持 red；根因治理继续归 [HWLAB #2055](https://github.com/pikasTech/HWLAB/issues/2055) 和 [HWLAB #2125](https://github.com/pikasTech/HWLAB/issues/2125)，不得在 UI、CLI renderer 或 analyzer 中做读侧 repair。

P9 多实例巡检与账号切换链路执行 issue 为 [#1017](https://github.com/pikasTech/unidesk/issues/1017)。P9 closeout 必须回写：SPEC P9 引用、registry 和两条 sentinel drill-down、旧 dsflash canary 迁移验证、账号切换 workflow/Secret sourceRef 验证、独立 Deployment/PVC/Service/SQLite/GitOps/Argo/public route prefix 证据、submit/command 失败处理、非阻塞计时告警证据、远程 PNG 截图布局复测，以及未完成阶段是否已拆出后续 issue。

P10 monitor-web 聚合执行 issue 为 [#1056](https://github.com/pikasTech/unidesk/issues/1056)。P10 closeout 必须回写：SPEC P10 引用、runner/web 职责拆分状态、Vue+TS monitor-web 迁移边界或短修边界、root 与至少一个 route prefix 的 browser render 证据、`web-probe sentinel dashboard verify|screenshot` 证据、publicExposure 和 runtime provenance、单哨兵 API 兼容性、未完成 monitor-web 架构项是否拆出后续 issue，以及 `unidesk-monitor` skill 是否记录当前操作面。

P11 monitor-web 观察面板治理执行 issue 为 [#1112](https://github.com/pikasTech/unidesk/issues/1112)。P11 的第一阶段必须先完成本 SPEC 收敛；SPEC 未合并前不得推进 Vue `monitor-web` 实现、CI/CD、GitOps、publicExposure 或部署代码。P11 实现 PR closeout 必须回写：SPEC P11 引用、Vue monitor-web 源码和 CI/CD 文件头部追溯、趋势曲线和运行时间线截图、固定视口三栏 overflow 摘要、cadence freshness 状态、env reuse/buildServices 证据、git mirror pre-sync/post-flush 证据、PipelineRun/Argo/GitOps/source alignment、root 与至少一个 sentinel detail 远程截图 localPath/SHA，以及超过两分钟 CI/CD 耗时是否已先从 env reuse/git mirror 方向优化。

P12 cadence 调度和 monitor-web 交互修复执行 issue 为 [#1123](https://github.com/pikasTech/unidesk/issues/1123)。P12 closeout 必须回写：SPEC P12 引用、两个 10m cadence sentinel 的 stale 证据、k3s CronJob/GitOps 调度器 due 判断和触发记录、auth sentinel Argo/source alignment、趋势曲线 hover 数值和时间截图/DOM 证据、三栏 sticky header 遮盖复测、远程 PNG localPath/SHA、k3s CronJob 状态、以及两个目标 sentinel 最新 run 已刷新到当前窗口的证据。

P13 D518 多 runner 强边界与 OTel 根因收敛执行 issue 为 [#1206](https://github.com/pikasTech/unidesk/issues/1206)。P13 closeout 必须回写：SPEC P13 引用、[#1208](https://github.com/pikasTech/unidesk/issues/1208)-[#1216](https://github.com/pikasTech/unidesk/issues/1216) 阶段状态、D518 双 sentinel 独立 Deployment/Service/PVC/CronJob/GitOps/Argo/public route 证据、route/API sentinelId 强断言、report/index 不串线证据、dashboard verify/screenshot localPath/SHA、k3s CronJob 调度证据、latest selected run 与 historical trend 状态分层证据、以及 OTel AgentRun namespace/trace gap 是否已解除或拆入后续 issue。
