# 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（由 P17 取代） |
| Monitor Web 观察面板治理实现引用版本 | draft-2026-06-27-p11-monitor-web-observability-dashboard; draft-2026-06-27-p12-cadence-scheduler-monitor-web |
| Monitor 中心持久化实现引用版本 | draft-2026-07-12-p17-monitor-central-persistence |
| Cadence/OTel 稳定性实现引用版本 | draft-2026-07-01-p15-cadence-otel |
| CI/CD source snapshot 实现引用版本 | draft-2026-07-01-p16-cicd-source-snapshot |
| 浏览器资源治理实现引用版本 | draft-2026-07-13-p18-browser-resource-guard |
| 外部表单工作流实现引用版本 | draft-2026-07-18-p19-external-form-workflow |
| 需求规格模板 | [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-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.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.sentinels[]` 多实例 registry、`observability.webProbe.monitor.configRef` 中心服务入口，以及各自 owning YAML 的引用图。
- 独立 sentinel runner、scheduler、scenario runner、artifact PVC、中心 Monitor ingest/query 服务、Host PostgreSQL、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 验证。
- 哨兵自身 CI/CD 的 k8s git-mirror source snapshot、PipelineRun source acquisition、GitOps publish 和 selected/latest closeout。
- 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-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.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 伪装执行隔离。runtime Deployment/Job、Service、artifact PVC、GitOps path、Argo Application 和 metrics label 必须按 sentinel id 独立；结构化 run/finding/locator 则统一进入中心 Monitor Host PostgreSQL。
- 中心 Monitor 索引、dashboard、metrics 和 maintenance 状态不得替代 `samples.jsonl`、`control.jsonl`、network/artifact JSONL 或 `analysis/report.json` 成为探针事实源。
- Dashboard 不负责修复 Workbench projection、trace timing、runner/envreuse 或 git mirror 慢路径；它只把 observe/analyze 已采集事实组织成可读的值守和分析入口。
- Web 哨兵不得通过降低 Playwright/Chromium 启动资源、禁用浏览器能力或自动刷新页面来规避 Workbench 卡死和内存膨胀；浏览器进程 RSS 是诊断证据，阻塞判定必须优先使用页面级 baseline 后的有效内存、CDP/Playwright 响应性和 YAML policy。

## 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`。 |
| Monitor 中心索引 | NC01 Host PostgreSQL 中由中心 Monitor 服务唯一写入和查询的结构化 run、finding、report payload、artifact locator 与必要状态时间线；它不是业务或探针事实源。 |
| legacy SQLite index | 切换前 runner PVC 上的历史轻量索引，只能作为一次性迁移输入和有界回滚快照，不能继续提供运行时读写或 fallback。 |
| 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。 |
| source snapshot | 哨兵自身 CI/CD 触发时由 k8s git-mirror 解析出的不可变源码快照，绑定 selected commit、mirror ref、PipelineRun、GitOps revision 和 runtime image。 |
| monitor-web | 独立于 sentinel-runner 的 Vue 3 + TypeScript + Vite 展示层，只消费中心 Monitor bounded API，承载 `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 摘要。 |
| 页面内存 baseline | web-probe 在每个 Playwright page/page epoch 上采集的初始浏览器运行指标；浏览器启动、空页和未加载目标 URL 前的基础成本只作为 baseline，不计入该页有效内存预算。 |
| 页面有效内存 | 同一 page/page epoch 当前 JS heap、DOM counter 或 runtime memory 指标扣除页面内存 baseline 后的增长量；是否 blocker 由 YAML browserFreezePolicy 控制。 |

## 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 状态。 |
| 受控资源 | Sentinel runner Deployment/Job、Service、artifact PVC、中心 Monitor Deployment/Service、Host PostgreSQL database/role/export/Secret consumer、ServiceAccount、NetworkPolicy、ConfigMap、publicExposure、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、artifact PVC、中心 ingest/query、Host PG、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、runner 隔离、账号切换 command、中心 API scope 和 report label | YAML配置、Wrapper边界、安全隔离 | 多哨兵巡检、账号链路值守 |
| PJ2026-0106050811 | Monitor 中心服务与 Web | 本规格 6.11 | runner/中心服务/Web 职责拆分、Host PG 唯一索引、中心 API、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工作台、发布集成、源码同步 | 可滚动上线和值守的统一观察面板 |
| PJ2026-0106050814 | 哨兵 CI/CD 可见性 | 本规格 6.14 | publish 阶段耗时、env reuse、docker cache、超时诊断、git mirror/Argo/runtime 收敛下一步 | 发布集成、源码同步、Monitor Web 观察面板治理 | 小改动滚动上线可诊断、可续跑、可验收 |
| PJ2026-0106050815 | Cadence/OTel 稳定性 | 本规格 6.15 | Kubernetes CronJob 周期巡检、状态缺口故障码、monitor-web cadence 可见性和 sentinel OTel span 合同 | Monitor Web 观察面板治理、发布集成、OTel、YAML运维 | JD01/v03 周期巡检恢复和后续防回归 |
| PJ2026-0106050818 | 浏览器资源治理 | 本规格 6.18 | 物理内存启动资格、短窗口最终复核、浏览器有界证据与精确收尾 | Wrapper边界、YAML配置、平台运维 | WebProbe 人工入口与 cadence 稳定运行 |

### 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[Per-sentinel runner]
    Scheduler[Scheduler]
    Adapter[observe CLI wrapper adapter]
    ArtPVC[(Immutable artifact PVC)]
    RunnerAPI[/health trigger artifact access]
    Metrics[/metrics]
    Scheduler --> Adapter
    Adapter --> ArtPVC
    Scheduler --> Metrics
    RunnerAPI --> ArtPVC
  end

  subgraph Monitor[Central Monitor]
    Ingest[Ingest API]
    Store[(NC01 Host PostgreSQL)]
    Query[Bounded query API]
    Dash[monitor-web]
    Ingest --> Store
    Store --> Query
    Query --> Dash
  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 --> ArtPVC
  Analyze --> Ingest
  Runner --> Web
  Dash -. HTTPS .-> Exposure
```

### 5.2 配置引用图

```mermaid
flowchart TD
  Root[config/hwlab-node-lanes.yaml<br/>targets.node.observability.webProbe] --> Entry[id/enabled/configRef]
  Root --> MonitorRef[monitor service 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 --> Cicd[cicd.d601-v03.yaml#sentinel.cicd]
  Refs --> SecretRefs[secrets.d601-v03.yaml#sentinel.secrets]
  MonitorRef --> MonitorRuntime[Monitor runtime owning YAML]
  MonitorRuntime --> PublicExposure[Monitor publicExposure owning YAML]
  MonitorRuntime --> PlatformDB[config/platform-db/postgres-nc01.yaml]
  PlatformDB --> MonitorSecret[Monitor DB export / Secret consumer]
  Scenarios --> PromptSets
  Scenarios --> ReportViews
  Scenarios --> AnalyzeThresholds[hwlab-node-lanes.yaml#...observe.analysisThresholds]
  PublicExposure --> Edge[PK01 Caddy + FRP managed block]
  SecretRefs --> Runtime
  Cicd --> Runtime
  MonitorSecret --> MonitorRuntime
```

配置引用图必须保持单向：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 --> Ingest[Monitor ingest]
  ReportJson --> ArtifactPVC[Runner artifact PVC]
  ReportMd --> ArtifactPVC[Runner artifact PVC]
  Ingest --> Store[(NC01 Host PostgreSQL)]
  Store --> ViewApi[bounded Monitor query API]
  Store --> ReportCli[sentinel report]
  ViewApi --> Dashboard[monitor-web]
  Store --> Metrics[Prometheus metrics]
  Store --> Validation[targetValidation]
```

`ReportCli`、dashboard、metrics 和 targetValidation 只能读取中心 Monitor 索引及其引用的 artifact/report 摘要。它们不得重新访问 Workbench、重新采样页面、重排 trace 行、重新分类 finding 或从 PostgreSQL 推导业务事实。

### 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 Mon as Monitor ingest / Host PG

  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-->>Mon: terminal run, report SHA, findings and locator
```

### 5.5 发布 maintenance 时序图

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

  CI->>Mon: maintenance/start release id
  Mon-->>CI: sampling continues, alert muted
  CI->>CP: rollout / Argo sync
  CP-->>CI: runtime healthy summary
  CI->>Mon: maintenance/stop
  Mon->>Run: trigger selected quick verify
  Run->>CLI: observe start/command/status
  CLI-->>Run: observer/run/stateDir
  Run->>Ana: analyze quick verify artifact
  Ana->>Mon: terminal ingest
  Mon-->>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 Run as Sentinel runner
  participant Mon as Monitor service
  participant Val as sentinel validate

  CP->>GitOps: publish digest-pinned manifests
  Argo->>Run: sync runner Deployment/Job/Service/PVC
  Argo->>Mon: sync Monitor Deployment/Service
  Val->>Run: /health, /metrics, artifact PVC
  Val->>Mon: /health, Host PG schema/query, monitor-web assets
```

哨兵自身 rollout 只验证 runner 与中心 Monitor 服务健康、配置装载、artifact PVC 可写、Host PG 可查询、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
  Store[(NC01 Host PostgreSQL)] --> OverviewApi[/api/overview]
  Store --> RunsApi[/api/runs filters cursor]
  Store --> FindingsApi[/api/findings aggregate]
  Store --> DetailApi[/api/runs/:id]
  Store --> ViewApi[/api/runs/:id/views]
  ArtifactLocator[artifact locator] --> ViewApi
  Artifacts[runner observe artifacts] --> ArtifactLocator
  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-010401080313-workbench-realtime-authority.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 的解释必须一致。

当 `web-probe` 被用于 Workbench smoke 或巡检时，smoke 目标是 Workbench 用户入口，不是 web-probe 自身。若观察到请求风暴、浏览器 freeze、内存上涨、submit/command 失败、trace rows 缺失或 final response 缺失，哨兵只能记录 blocker、root cause、artifact 和 drill-down；修复责任必须回到 [Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 或对应业务规格。不得为了让哨兵变绿而减少采样、自动刷新页面、重建 page、关闭 freeze/memory 检测、降低 finding 等级、修改 Playwright 启动参数或把业务 smoke 改成 web-probe 工具自检。

### 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 哨兵多实例配置必须通过 node/lane root YAML 的 `observability.webProbe.sentinels[]` registry 进入，中心服务通过 `observability.webProbe.monitor.configRef` 进入。sentinel registry 项只能声明 `id`、`enabled` 和 `configRef`，再由 sentinel 管理 YAML 引用 runtime、workflow/scenario、promptSet、reportView、CI/CD 和 Secret owning YAML；Monitor 管理 YAML 独立引用 runtime、publicExposure、persistence、CI/CD 和 Secret owning YAML。旧单实例 `sentinel` 与 `monitorRoot` 在 P17 切换时删除，不作为兼容入口保留。

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 哨兵必须拆成 per-sentinel runner 与中心 Monitor 服务。runner 负责编排既有 observe/analyze、生成不可变 artifact、暴露执行健康/受控触发/locator 访问；中心 Monitor 服务负责 ingest、Host PostgreSQL 持久化、bounded query API、metrics 和 monitor-web 静态资源。两者都不得复制第二套 DOM/网络采样、截图、Workbench 读取逻辑或 finding 分类。

每个 runner 的 PVC 只保存 `.state/web-observe` artifact 和切换前冻结的 legacy SQLite 快照。NC01 Host PostgreSQL 保存 runner identity、run、finding、report payload、artifact locator 和必要状态时间线；只有中心 Monitor 服务持有数据库连接并写入。结构化索引不得替代 JSONL/report 事实源，不参与 Workbench lifecycle、trace 顺序、final response 或业务状态仲裁。

终态 ingest identity 固定为 `(sentinelId,node,lane,runId)`；相同 identity 与相同 payload hash 必须幂等，相同 identity 与不同 payload hash 必须结构化拒绝。runner 在 analyze 后同步提交已有 report/finding/locator，并对瞬时失败做 YAML 声明的有界重试；最终失败必须显示 `monitor-ingest-failed` 或等价语义，允许用同一不可变 artifact 显式重提，禁止写本地 SQLite fallback、永久 outbox 或第二索引。

runner `/health` 必须覆盖配置装载、scheduler/CronJob 观察、artifact PVC 可写、analyze 可执行性和中心 ingest 可达性；中心 Monitor `/health` 必须覆盖配置、Host PG 连接/schema、ingest/query 和前端资产。Pod 重建不能靠扫描 PVC 或补造历史恢复中心索引；进行中 run 可以按已有执行事实标记 `interrupted` 并重新调度，不能静默假绿。

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

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-004 | 报告视图 | PJ2026-0106050804 报告视图 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.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 收敛容量或池化参数。

请求风暴和 freeze 判定必须保留请求族、page/page epoch、页面内存 baseline 后有效内存、CDP/Playwright 响应性、control command 结果和 OTel trace/span 关联摘要。具体 policy 数值来自 YAML/source-of-truth；报告只展示字段、状态、来源和是否命中 policy，不在 dashboard、report 文案或源码中复制硬编码阈值。若当前 closeout 明确裁剪为“未复现请求风暴或浏览器卡死”，可以把 trace rows/final response 投影为空列为非阻塞剩余风险，但不得写成 Workbench 投影问题已修复。

### 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`，runner 与中心 Monitor 的镜像、GitOps path、Argo Application、中心 publicExposure 和 targetValidation 分别由对应 owning YAML 声明。builder 类型必须来自 YAML，不得依赖 operator 本地 dirty worktree。

哨兵自身 CI/CD 的 source identity 必须来自 k8s git-mirror source snapshot。`trigger-current` 应先通过 YAML 声明的 git-mirror cache/service 在 k8s 内解析并同步 selected commit，再把同一 source snapshot 注入 publish PipelineRun、GitOps 写回、status 和 closeout。operator host 上的 `git ls-remote`、`git fetch`、`git clone`、`git rev-parse HEAD` 和固定 host worktree 读写不得参与正式 source selection。

publish PipelineRun 的 source step 只能消费 source snapshot 的 commit-pinned mirror ref、stageRef、PVC 或 bundle artifact；不得把 mutable `refs/heads/<branch>` 作为本轮 source identity，也不得在 mirror 对象缺失时回退到 GitHub direct clone 或 host workspace repair。mirror 缺对象时必须结构化失败为 `source-snapshot-missing` 或等价故障码，并输出受控 source-mirror sync/ensure 命令。

哨兵 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` 时必须输出 warning，并先优化等待阶段耗时，不得继续把长业务验证塞在部署同步路径里死等。`sentinel validate --quick-verify --confirm --wait` 和 maintenance stop quick verify 才执行 targetValidation 业务验证；业务 quick verify 的等待预算由 YAML `targetValidation.maxSeconds` 控制。计时超限本身只作为非阻塞告警；只有真正影响 Code Agent 多轮业务链路、submit/command 执行、trace/final 可见性或 session 连续性的失败才构成 targetValidation blocker。不得通过减少业务轮次、吞掉 submit 失败、fallback 到第二执行路径或读侧 repair 来消除红灯。

status/closeout 必须同时展示 selected source snapshot、latest mirror head、PipelineRun source snapshot、GitOps revision、runtime image digest 和 runtime observed 状态。若 `master` 在发布过程中继续前进，只能标记为 `latest-drift` 或 `superseded`；不得把 selected commit 已发布成功的结果覆盖成“追最新失败”。

### 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 新观察面板能力的主要承载面。

P15 cadence/OTel 范围内新增或修改的 CronJob renderer/status probe、runner health/overview、quick verify record path、monitor-web cadence 展示和 OTel emitter 源码文件头部必须标注 `SPEC: PJ2026-01060508 Web哨兵 draft-2026-07-01-p15-cadence-otel`。

P17 中心持久化范围内新增或修改的 Monitor ingest/query、Host PG store/schema、SQLite export/import、runner terminal submit、monitor-web API client、CLI report/status、YAML renderer 和 cutover 工具源码文件头部必须标注 `SPEC: PJ2026-01060508 Web哨兵 draft-2026-07-12-p17-monitor-central-persistence`。

实现文件不得只写 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、YAML targetValidation budget、severity counts 和最新 report SHA。超过 YAML targetValidation budget 的 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 自身制造额外压力。

长期权威观察面板是 Vue `monitor-web`，不是 runner 内置 dashboard。切换前 runner 页面只允许用于迁移对照，切换发布必须删除其查询和展示入口；趋势曲线、固定视口三栏、运行时间线、多哨兵聚合、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[]` 为唯一 runner registry。每个 registry 项必须通过 `configRef` 指向独立 sentinel 管理 YAML，管理 YAML 再声明 runtime、workflow/scenario、promptSet、reportViews、cicd 和 secrets configRefs；中心 Monitor 由独立 `observability.webProbe.monitor.configRef` 声明。对 runner 的 image、control-plane、validate 和执行操作必须显式携带 `--sentinel <id>`；全局 report/overview 默认走中心 API，并支持显式 scope。

每个 sentinel 必须拥有独立的 runner Deployment/Job、ServiceAccount、ClusterIP Service、artifact PVC、GitOps path、Argo Application、metrics label 和稳定 `(sentinelId,node,lane)` identity；不得共享一个执行 Pod/PVC 后再用 scenario id 伪装隔离。结构化 run/finding/locator 统一写入中心 Host PG，并以稳定 identity、FK 和 scope 索引隔离，不再声明 per-sentinel SQLite path 或 report index namespace。

`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，不重新访问 Workbench、不保存第二套截图、不打印账号凭据。

公网只暴露中心 monitor-web；runner Service 不按 sentinel 单独公开。多实例 public exposure 复测必须通过受控 `web-probe screenshot` 或沉淀后的 command 远程截图能力完成，并把 PNG 保存到调用者 `/tmp` 下用于人工布局分析。修复 dashboard 布局问题后，复测截图必须覆盖 root dashboard 和至少一个中心 API 驱动的 sentinel detail route。

### 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工作台、多实例与账号切换 |

P17 起，Web 哨兵运行面必须区分 `sentinel-runner`、中心 `monitor-service` 与 `monitor-web`。runner 只负责采样、分析、不可变 artifact、执行健康和终态提交；中心 service 是 Host PG 唯一 writer/query authority，负责 global overview/runs/findings/detail、maintenance/cadence 结构化状态与 locator；monitor-web 只负责展示和人类值守信息架构。禁止把 monitor-web 继续挂在任一 runner 上作为 `runner-served-bridge`。

中心 Monitor 配置必须是 YAML-first。node/lane、namespace、Deployment、Service、publicExposure、Host PG database/role/export/Secret consumer、ingest/query timeout、静态资源托管方式、RBAC、NetworkPolicy 和 migration/cutover mode 都必须来自 owning YAML 或 configRef。root `observability.webProbe.sentinels[]` 仍是 enabled sentinel registry；数据库或 Kubernetes discovery 只能与 registry 做一致性校验，不能写回第二 source of truth。

Runner Service/Pod 必须带 `unidesk.ai/web-probe-sentinel-id`、node、lane、workspace 和 component label，供中心控制面做健康、触发与 artifact locator 可达性检查。中心 query 绝不能按请求 fan-out runner API、读取 runner SQLite 或扫描 PVC；runner 不可用时，已经进入 Host PG 的历史仍必须可查，只有对应 artifact locator 显示不可达。Prometheus/ServiceMonitor 只用于低基数 metrics scrape，不承载 report drill-down。

`monitor-web` 前端目标技术栈为 Vue 3 + TypeScript + Vite，并与 HWLAB Cloud Web 的组件拆分、typed API client、状态管理、加载/空态/错误态、Markdown/代码块渲染和样式约定对齐。前端只能消费中心 bounded API，不允许 N+1 拉取 runner detail 或客户端合并 global latest。旧 runner 内置 dashboard/静态资产在切换完成后删除，不作为兼容入口保留。

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>` 必须从同一中心 API 展示单哨兵 runs/findings/detail/trace-frame。删除或重启一个 runner 只能让对应 execution/artifact 可达性显示 degraded，不得清空已持久历史或阻断其他 runner 数据。所有 API 必须 bounded、分页、redacted，不打印 Secret、prompt 原文、provider payload、cookie、完整 stdout/stderr 或完整 report。

Host PG 首版数据模型必须至少包含 runner identity、run、finding、run payload、artifact locator、timeline event、schema migration 和 import manifest。run identity 使用 `(sentinelId,node,lane,runId)` 唯一约束；finding 和 payload 以 run FK 关联；artifact locator 保存 owner node/lane/PVC、stateDir、relative path、SHA、size 和 kind，不保存 artifact blob。全局及 scoped latest 统一按 `updatedAt DESC, runId DESC` 选择，所有列表使用稳定 cursor，不允许各 runner 自己定义 latest。

中心 ingest 首版使用同步 HTTP 提交，不引入 Kafka、第二数据库或长期 outbox。runner 只提交已有 analyze/report 事实；中心在一个 PG transaction 内写入 run、finding、payload、locator 和 timeline。提交失败时 run 执行结果与 `monitor-ingest-failed` 必须同时可见；对同一不可变 report 的显式重提属于恢复同一事实，不得修改 payload、补造 report 或把失败 run 静默标成已记录。

SQLite 到 Host PG 的迁移必须先恢复并验证 YAML 声明的 Host PG role/database/export/Secret consumer，再从 resolved registry 生成实际 source 清单。受控 cutover 依次执行：暂停新 run 并等待 active run 结束、对每库记录 fingerprint/integrity/schema/row count、创建一致只读快照、单 source transaction 导入、校验行数/关键字段/latest/locator SHA 与可达性、切换 runner writer 和中心 query、恢复 cadence。切换前允许回到冻结快照；PG 接管新写入后不得回写或重新服务 SQLite。

实现可以分两次自动发布：第一次交付 PG capable 的中心 service、store 和迁移工具，但生产读写仍保持旧权威且不得双写；第二次在迁移校验成功后一次性切换 writer/query/UI/CLI，并删除 runner SQLite/query/dashboard 路径。PR 合并后只能观察自动 GitHub webhook → Gitea mirror → PaC → CI/CD → GitOps/Argo 链路，自动链路不通时修自动链路，禁止手工补触发。

### 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。

P17 删除 `runner-served-bridge`。sentinel runner Pod/Job 只承载执行 adapter、artifact PVC、health、metrics 和中心 ingest client；若运行单元没有完整 repo 配置、`trans`、Chromium 或 observe 依赖，不得自行 SSH/回调宿主机触发巡检。周期巡检仍由受控 node/lane CronJob 读取同一 YAML registry、scenario/workflow cadence 和 targetValidation timeout，并触发现有 `web-probe sentinel validate --quick-verify --confirm --wait` 语义；它不实现第二套采样、analyze、finding 分类或 report 写入。

调度器必须由目标 node/lane 的 k3s CronJob/GitOps 受控入口周期调用，默认 tick 间隔不得替代 YAML cadence；due 判断读取中心 Monitor 的 latest 与 YAML cadence，不读取 runner 私有索引。每次 tick 必须输出 sentinel id、cadence、latest run age、due、trigger status、latest run id 和下一步 drill-down。触发失败要区分业务 finding、命令 submit/control 失败、中心 query/ingest 不可达、lock-held 和 timeout；业务 finding 已产生并成功 ingest 新 run 时不得把 scheduler 本身标为 infra blocker。

`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` 与中心 Monitor service 的 CI/CD 必须和架构一起交付。YAML 必须声明 source、build context、Node/Bun/Vite 构建环境、env image、dependency cache、registry image、GitOps path、Argo Application、Service、publicExposure、Host PG Secret consumer、runner control-plane discovery selector 和 screenshot 验收命令。CI 读源码必须优先走 node/lane 声明的 git mirror read URL；PR 合并后只允许自动链路完成 mirror、PaC、PipelineRun、GitOps 和 Argo 收敛。

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 后只记录超时。

发布成功判据必须同时覆盖中心 `/health`、Host PG schema/read-write probe、Vue assets 和 browser render，不能只看静态资源 200。closeout 必须记录 Vite 产物 hash、中心 API、root 与至少一个 `/sentinels/<id>` 详情页、远程 PNG localPath/SHA、DOM/overflow、Argo/runtime/source/GitOps alignment，以及停一个 runner 后历史仍可读而 locator 显示 degraded。禁止手工触发 mirror、PipelineRun、Argo sync/refresh 或补做 CI/CD。

### 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/artifact PVC。每个 sentinel 必须有独立 runtime configRef，至少独立声明 runner Deployment/Job、Service、ServiceAccount、PVC、stateRoot、CronJob、GitOps path 和 Argo Application；公网 FRP/Caddy 只属于中心 monitor-web。`observeWrapperRef` 不得使用 `sentinels[0]` 这类位置索引，必须由 selected sentinel id 解引用或用等价稳定 id 绑定。

runner API 只保留 health、受控 trigger 与 artifact locator 访问，不再提供 overview/runs/findings/report。中心 API 必须按 `sentinelId`、node、lane、scenario、run identity 做显式 scope 与排序；route scope 与 registry/数据库 identity 不一致时返回结构化 `sentinel-route-mismatch`，不允许 fallback 到其他 sentinel 的 latest，也不允许前端过滤后继续展示。

状态语义必须区分 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 selected sentinel、overview scope、runs rows 的 `sentinelId` 和 public URL route。任何 dsflash route 返回 fake-echo 数据、detail route 返回空 body、root 绑定单 runner 或页面绕过中心 API 的情况都必须失败并给出有界证据。

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，不得静默跳过。

### 6.14 OPS-SENTINEL-REQ-014 Web 哨兵 CI/CD 可见性与续跑边界

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-014 | 哨兵 CI/CD 可见性 | PJ2026-0106050814 哨兵 CI/CD 可见性 | 发布集成、源码同步、Monitor Web 观察面板治理、YAML运维 |

本阶段执行 issue 为 [#1285](https://github.com/pikasTech/unidesk/issues/1285)。`web-probe sentinel control-plane trigger-current --confirm --wait` 的默认输出必须把 source mirror、publish、git mirror flush、Argo apply 和 runtime observed 明确分阶段展示。`confirmWait.maxSeconds` 仍是 YAML 声明的交互等待预算；超过预算时 CLI 必须停止盲等并返回结构化阶段归因，不能只输出 `job-timeout`。

publish 结果必须输出 env reuse 摘要、依赖复用路径、docker build cache 摘要、镜像 digest、GitOps commit、各阶段耗时和 bounded 日志摘要。env reuse 摘要至少包括 reuse mode、node deps path、path 是否存在、依赖项数量或等价命中信号；docker cache 摘要至少包括 build log 中的 cache hit 行数、构建步骤行数和 layer cache 口径。上述字段只作为可见性证据，不新增业务门禁，也不得打印 Secret、token、cookie、provider payload 或完整无界构建日志。

publish Job 未在等待预算内结束时，CLI 必须输出 job 名称、pod、pod phase、当前阶段、已完成阶段、最近日志摘要和可安全继续的 drill-down 命令。drill-down 命令必须优先指向受控 UniDesk CLI；只读 k3s 日志或 describe 可以通过 `trans <node>:k3s kubectl ...` 作为诊断入口，但不得把手工 `kubectl apply/delete/patch` 变成正式控制面。

当 publish 已产出镜像 digest，但 GitOps、git mirror、Argo 或 runtime observed 未收敛时，CLI 必须直接给出下一步：先查看 `web-probe sentinel control-plane status` 和 `hwlab nodes git-mirror status`，若 GitOps pending flush 则走 `hwlab nodes git-mirror flush --confirm --wait`，若 Argo/runtime stale 则走 `web-probe sentinel control-plane apply --confirm --wait`。操作员不得靠猜测在裸 `kubectl/argo` 和多条旧路径之间切换。

JD01/v03 `jd01-web-probe-sentinel` 的小改动滚动上线是本阶段验收入口。closeout 必须记录 SPEC P14 引用、source commit、publish job、digest、GitOps revision、git mirror pending/inSync、Argo/runtime alignment、`validate`、远程 dashboard screenshot 和 latest report 证据。若总等待仍超过 YAML confirmWait 或 targetValidation 预算，closeout 必须记录阶段归因、env reuse/cache 摘要和下一步优化方向；不得通过单纯放宽 YAML 预算收口。

### 6.15 OPS-SENTINEL-REQ-015 Cadence 调度稳定性与 OTel 覆盖

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-015 | Cadence/OTel 稳定性 | PJ2026-0106050815 Cadence/OTel 稳定性 | Monitor Web 观察面板治理、发布集成、OTel、YAML运维 |

本阶段执行 issue 为 [#1372](https://github.com/pikasTech/unidesk/issues/1372)，阶段子 issue 为 P0 [#1374](https://github.com/pikasTech/unidesk/issues/1374)、P1 [#1377](https://github.com/pikasTech/unidesk/issues/1377)、P2 [#1375](https://github.com/pikasTech/unidesk/issues/1375)、P3 [#1378](https://github.com/pikasTech/unidesk/issues/1378) 和 P4 [#1376](https://github.com/pikasTech/unidesk/issues/1376)。

Web 哨兵周期巡检必须由目标 node/lane 的 Kubernetes CronJob/GitOps 受控对象承载。CronJob 的 enabled、scenarioId、cadence 来源、startingDeadlineSeconds、successfulJobsHistoryLimit、failedJobsHistoryLimit、activeDeadlineSlackSeconds、ttlSecondsAfterFinished、backoffLimit、concurrencyPolicy、targetValidation.maxSeconds、sampleInterval、screenshotInterval、maxRunSeconds、retention 和 OTel endpoint/sampling 都必须来自 owning YAML/configRef；代码只能解析、校验和渲染，不得用隐藏默认补阈值、历史保留、deadline、timeout、并发策略或采样策略。

`web-probe sentinel control-plane status` 必须把 CronJob 作为独立 observed check，而不是只相信 Argo `Synced/Healthy`。当 YAML 启用 cadenceScheduler 但线上缺 CronJob 时，状态必须 blocked，故障码固定为 `sentinel-cadence-cronjob-missing`；schedule 不一致使用 `sentinel-cadence-cronjob-schedule-mismatch`；CronJob suspend 使用 `sentinel-cadence-cronjob-suspended`。状态输出至少展示 CronJob name、namespace、schedule/expectedSchedule、lastScheduleTime、lastSuccessfulTime、active job count、jobCount 和 latest job name。

`monitor-web` 必须把 cadence freshness 作为一等状态：显示 YAML expected cadence、scheduler heartbeat age、latest run age、latest analyzed report age、active runs、planned runs、stale multiple、CronJob 观察状态和 OTel coverage/gap。中心 API 未取得 Kubernetes CronJob observed fact 时，页面必须显式显示 `control-plane-status-required`，不得让用户误以为 CronJob 已观察通过。

Web 哨兵必须向平台 OTel 后端发出有界、脱敏的 span 或在状态中显式标记 instrumentation gap。P15 span 名称固定为：`web_probe_sentinel.scheduler.heartbeat`、`web_probe_sentinel.cadence.expected`、`web_probe_sentinel.cadence.cronjob_rendered`、`web_probe_sentinel.cadence.cronjob_observed`、`web_probe_sentinel.quick_verify.job_start`、`web_probe_sentinel.quick_verify.job_finish`、`web_probe_sentinel.record_run`、`web_probe_sentinel.scheduler_gap.detected`。属性至少包含 node、lane、sentinelId、scenarioId、runId、cronJobName、jobName、podName、namespace、cadence、status、exitCode、failureKind、gitopsRevision、sourceCommit、imageDigest 和 valuesRedacted；不存在的属性可以省略但不得打印 Secret、prompt、cookie、provider payload 或完整 stdout/stderr。

CI/CD rollout 门禁仍只验证配置声明的 `/health` endpoint。web-probe quick verify、Playwright/browser render、dashboard screenshot 和 OTel trace search 都是独立的 post-deploy evidence；不得重新塞回 `trigger-current --confirm --wait` 的同步门禁，也不得引入 Docker daemon/socket 依赖。

### 6.18 OPS-SENTINEL-REQ-018 浏览器资源治理

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-018 | 浏览器资源治理 | PJ2026-0106050818 浏览器资源治理 | Wrapper边界、YAML配置、平台运维 |

- 启动资格：
  - 所有会创建 Playwright/Chrome 的 WebProbe 人工入口与 sentinel cadence 必须在真正启动浏览器前读取目标主机 `/proc/meminfo` 的 `MemAvailable`；
  - 启动阈值、比较语义、最终复核等待和浏览器证据上限只由 owning YAML 提供；
  - 启动阈值的唯一事实源是 `config/hwlab-node-lanes.yaml#templates.hwlabV03.webProbeWorkbench.resourcePolicy.memoryStartGuard.thresholdBytes`；
  - 规格、长期参考、skill、源码和测试不得复制阈值数值，也不得提供隐藏默认值或 fallback；
  - 除非用户明确授权修改启动门槛，否则任何任务、代理、自动链和运行面调试都不得改变该字段；
  - swap 作为独立压力信号展示，不得计入启动资格。
- 当前 HWLAB v0.3 策略：
  - 人工入口按 owning YAML 的 `manualComparator` 比较 `MemAvailable` 与 `thresholdBytes`，命中时阻断，并提示通过受控 GC 完成 plan、run、终态查询和重新读取；
  - sentinel cadence 按 owning YAML 的 `sentinelComparator` 比较，命中时跳过本轮并等待下一 cadence，不创建 observer 或 Chrome，也不自动执行 GC。
- 并发启动保护：
  - 只允许使用覆盖“最终重新读取 `MemAvailable` 到确认真实 Chrome/Chromium executable 已就绪”这一实际风险窗口的最小锁；
  - 确认就绪后必须立即释放；
  - 不得扩展为业务任务租约、第二生命周期 authority、证明链、通用状态机或新的服务合同。
- 终态收尾：
  - 成功、失败、timeout 和 signal 路径都必须关闭 context、browser 和本次启动的精确 process group；
  - 进程归属只以 `/proc` 中的实际 executable、PID/PGID 与精确后代关系判定；
  - 不接受 Playwright driver 名称或结构化输出自报成功；
  - 禁止 `pkill`、`killall` 和按名称批量终止。
- 证据容量：
  - 截图默认使用 owning YAML 声明的 viewport 模式，只有显式人工参数可以请求 full-page；
  - network、failure、response body、性能、截图、样本和历史证据必须有 YAML 上限；
  - 不得用无限数组、无限响应体或 full-page 默认值放大 WebProbe 自身内存。

### 6.19 OPS-SENTINEL-REQ-019 受控外部表单工作流

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-019 | 受控外部表单工作流 | PJ2026-0106050819 外部表单工作流 | Wrapper边界、Secret、浏览器资源治理 |

- 声明和复用：
  - 工作流必须由 YAML 或 JSON 文件声明；
  - node、lane、origin、viewport、等待预算、状态目录、允许域名、Secret sourceRef 和动作列表必须来自声明；
  - CLI 和 runner 不得写死站点、账号、身份证号或一次性申请数据。
  - 开发 smoke 可以声明仓库内无真实 PII 的 HTML fixture，由同一 runner 启动仅监听 loopback 的临时 HTTP 服务；
  - fixture 服务必须随 workflow 精确回收，不得替代真实 origin 的交付验收。
- 生命周期：
  - CLI 必须提供 `start`、`status`、`continue` 和 `stop` 短连接动作；
  - `start` 返回稳定 workflow id，不等待人工验证码；
  - runner 在验证码、邮箱确认或缺少人工字段时保持受控浏览器会话并进入 `paused`；
  - `continue` 只向指定暂停点注入一次性值并恢复执行；
  - `stop` 只终止该 workflow 的精确进程及浏览器后代。
- 动作合同：
  - 通用动作至少覆盖导航、文本填写、选择、勾选、点击、文件上传、等待、截图、暂停和保存草稿；
  - 工作流可以声明有界只读控件检查动作，用于获取最多 40 个控件的标签、ID、名称、类型、占位符、
    截短可见文字、类名和内联点击属性；
  - 控件检查默认 selector 为 `input, button, a, select, textarea`，不得读取或输出 `value`、Cookie、
    页面存储、输入控件文字或其他表单值；
  - selector、目标值引用和完成条件必须显式声明；
  - 本地上传文件必须按 YAML 大小上限进入 workflow 私有目录，并在 runner 终态删除；
  - 普通 `click` 不得操作 submit 控件，提交控件必须使用显式 `submit` 动作；
  - 最终不可逆提交动作默认拒绝，只有工作流声明允许且命令显式确认时才能执行。
- Secret 和 PII：
  - Secret 只从声明的 sourceRef 解析，在受控 runner 内短暂注入；
  - 密码、Cookie、验证码、身份证号和完整表单值不得进入 CLI 输出、日志、issue evidence 或截图文件名；
  - 默认输出只披露字段标识、presence、fingerprint、完成度和 `valuesRedacted=true`。
- 证据和恢复：
  - 状态必须有界披露 phase、当前动作、最终 URL、DOM/网络/console/pageerror 摘要、截图引用和字段完成度；
  - 控件检查结果最多保留 40 条，单项文字和属性必须限长并经过现有 Secret 脱敏；
  - artifact、状态和 continuation 文件必须使用受限权限；
  - timeout、失败、人工停止和正常结束都必须复用 OPS-SENTINEL-REQ-018 的浏览器资源回收合同。

## 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 引用、YAML wait-budget 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 验证、独立 runner Deployment/PVC/Service/GitOps/Argo 与中心索引 scope 证据、submit/command 失败处理、非阻塞计时告警证据、远程 PNG 截图布局复测，以及未完成阶段是否已拆出后续 issue。

P10 monitor-web 聚合执行 issue 为 [#1056](https://github.com/pikasTech/unidesk/issues/1056)。P10 的 runner fan-out/runner-served-bridge 方案已由 P17 取代；后续 closeout 只保留可复用的 Vue 信息架构、browser render、dashboard verify/screenshot、publicExposure 和 runtime provenance 证据，不再以单哨兵查询 API 兼容性作为门禁。

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 独立 runner Deployment/Service/PVC/CronJob/GitOps/Argo 证据、中心 route/API scope 强断言、report/index 不串线证据、dashboard verify/screenshot localPath/SHA、k3s CronJob 调度证据、latest selected run 与 historical trend 状态分层证据，以及 OTel AgentRun namespace/trace gap。

P14 Web 哨兵 CI/CD 可见性执行 issue 为 [#1285](https://github.com/pikasTech/unidesk/issues/1285)。P14 closeout 必须回写：SPEC P14 引用、source commit、PR/merge commit、JD01/v03 `jd01-web-probe-sentinel` publish job、digest、GitOps revision、git mirror flush 状态、Argo/runtime observed alignment、`validate`、dashboard screenshot、latest report，以及超过 YAML 等待预算时的结构化阶段归因和可续跑命令。

P15 Cadence 调度稳定性与 OTel 覆盖执行 issue 为 [#1372](https://github.com/pikasTech/unidesk/issues/1372)。P15 closeout 必须回写：SPEC P15 引用、[#1374](https://github.com/pikasTech/unidesk/issues/1374)-[#1378](https://github.com/pikasTech/unidesk/issues/1378) 阶段状态、JD01/v03 `jd01-web-probe-sentinel` CronJob manifest/GitOps/Argo/runtime observed 证据、`sentinel-cadence-cronjob-missing` 防回归状态、monitor-web cadence/OTel coverage 显示、OTel trace search 或 instrumentation-gap 证据、受控 rollout/publish job、GitOps revision、source commit、dashboard/health 验收，以及 CI/CD 门禁仍只验证 `/health` 的证据。

P17 Monitor 中心持久化与架构重构执行 issue 为 [#1868](https://github.com/pikasTech/unidesk/issues/1868)，P0 调研为 [#1869](https://github.com/pikasTech/unidesk/issues/1869)、[#1870](https://github.com/pikasTech/unidesk/issues/1870) 和 [#1871](https://github.com/pikasTech/unidesk/issues/1871)。P17 必须按“Host PG 前置健康、中心 store/ingest/query、runner terminal submit、一次性迁移与原子切换、monitor-web/CLI 中心读取、自动发布与原入口验收”顺序推进。closeout 必须记录 SQLite 冻结 fingerprint/行数、PG 导入校验、global latest 规则、artifact locator 可达性、runner 停机后历史可读、旧 SQLite 与 runner dashboard 已退出读写路径，以及 PR 合并后的自动 CI/CD 证据。

P18 浏览器资源治理执行 issue 为 [#1907](https://github.com/pikasTech/unidesk/issues/1907)。P18 closeout 必须回写：

- owning YAML 配置引用和所有浏览器创建入口矩阵；
- `MemAvailable` 与 swap 分离、人工阻断和 cadence 跳过边界；
- 精确 context/browser/process-group 收尾和证据容量上限；
- 无真实浏览器的边界测试和 NC01 只读资源复核。

P19 受控外部表单工作流执行 issue 为 [#2501](https://github.com/pikasTech/unidesk/issues/2501)。P19 closeout 必须回写：

- 工作流声明、Secret sourceRef 和 node/lane/origin 配置引用；
- `start/status/continue/stop` 生命周期及验证码暂停续填证据；
- 默认拒绝不可逆提交和显式确认边界；
- 无真实 PII fixture 的最小 smoke、脱敏输出和精确浏览器回收证据。
