# PJ2026-010103 HWPOD服务

## 修改历史

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

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

## 正文

## 实现引用

- 当前实现引用：
  - `draft-2026-07-10-g14-wsl-python-hwpod-node`。

## Windows Python 节点注册与路由

- 注册模型：
  - HWPOD 服务支持多个主动出站 Windows Python 节点；
  - WebSocket 注册表以唯一 nodeId 路由；
  - 新连接接管同一 nodeId 时，旧连接必须断开并暴露单活切换；
  - 未注册节点不得接收节点操作。
- 认证模型：
  - cloud-api 必须从 SecretRef 读取节点 WebSocket 凭据；
  - 节点必须在握手时携带对应凭据；
  - 凭据缺失或不匹配必须返回 `hwpod_node_ws_token_invalid` 或等价结构化阻塞；
  - 不得保留匿名生产注册或直连地址兜底。
- 路由与能力：
  - 调度必须按 plan.nodeId 选择注册连接；
  - 云端必须使用节点实际注册的 capabilities；
  - 静态 supportedOps 与节点实际上报不一致时必须暴露 capability mismatch；
  - direct URL、SSH reader 和服务端本地挂载不得替代节点注册表。
- 可观测性：
  - 状态必须显示 nodeId、版本、平台、能力、最近心跳和诊断摘要；
  - 输出不得包含 token、Authorization 或可复用凭据；
  - 离线、身份不匹配、认证失败、能力不匹配和操作失败必须分别分类。
- 配置归属：
  - Secret 名称、sourceRef、targetKey、节点身份和路由事实以 owning YAML 为准；
  - 规格不保存具体 Secret 值、地址、超时或重连参数。

## PJ2026-010103 HWPOD服务需求规格

## 1. 文档控制

| 字段 | 内容 |
| --- | --- |
| 编号 | PJ2026-010103 |
| 短名 | HWPOD服务 |
| 层级 | L2 课题 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-25-p0-web-caserun-e2e; draft-2026-07-13-p0-cloud-console |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-0101 硬件池](PJ2026-0101-hardware-pool.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |

本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版：正文只保留 HWPOD 服务的稳定使命、范围、术语、系统边界、内部分工和原子需求。

## 2. 目的和范围

### 2.1 目的

HWPOD服务负责服务端资源注册、健康、租约、占用释放、权限交接、请求接收、节点路由和结果归属，使 HWPOD 工具和上层任务能通过服务端 authority 访问真实硬件资源。

本课题的目标状态是：服务端只路由已声明、可用、已授权且租约一致的资源，并把每次操作结果归属到明确 HWPOD、node、租约和调用方。

在 Web CaseRun 场景中，HWPOD服务是 Cloud API、HarnessRL、AgentRun 和用户 PC 侧 HWPOD node 之间唯一的硬件资源 authority。Cloud Web、web-probe、CLI 和 Agent 都不得直接连接本地 gateway 或旧运行面来判定硬件成功。

### 2.2 范围内

- HWPOD registry、资源注册、runtime spec CRUD、spec 摘要、authority 和版本来源。
- HWPOD node 心跳接入、健康状态、可用性、能力摘要和路由状态。
- 租约、占用、释放、冲突处理、超时释放和写操作保护。
- 工具/API 请求接收、目标解析、节点路由、超时和错误分类。
- operation result 的归属、查询、摘要和对 HarnessRL/Agent编排/客户端的交接。
- Web CaseRun 对 HWPOD readiness、租约、路由、operation result、capability mismatch 和结构化 blocker 的消费边界。

### 2.3 范围外

- HWPOD spec 字段和能力模型归 [PJ2026-010101 HWPOD标准](PJ2026-010101-hwpod-standard.md)。
- CLI 命令形态、工具输出和 workspace 内调用归 [PJ2026-010102 HWPOD工具](PJ2026-010102-hwpod-tools.md)。
- 节点侧适配器执行和原始硬件事实生产归 [PJ2026-010104 AI网关](PJ2026-010104-ai-gateway.md)。
- 用户身份、API key、额度和租户策略归 [用户管理](PJ2026-0105-user-management.md)。

## 3. 术语表

| 术语 | 定义 |
| --- | --- |
| registry | 服务端维护的 HWPOD 资源目录，包含身份、spec 摘要、状态和路由信息。 |
| authority | 对 HWPOD 资源事实具有当前解释权的服务端或配置来源。 |
| 租约 | 一次资源占用关系，约束调用方、HWPOD、操作类型、超时和释放。 |
| 路由 | 服务端把 HWPOD 操作请求转发到正确 HWPOD node 或 AI 网关的过程。 |
| operation result | 服务端接收并归属的一次硬件操作结果。 |
| CaseRun 调用方 | HarnessRL 为一次 CaseRun 持有的硬件操作调用上下文，至少携带 runId、caseId、actor、HWPOD 和租约摘要。 |
| topology read model | 由 HWPOD 服务拥有的 node、HWPOD、声明/实际能力、readiness、占用和 blocker 的有界查询投影。 |

## 4. 系统边界和接口

本规格把 HWPOD服务作为硬件池的服务端资源管理层看待；本章只描述输入、输出和责任边界。

| 边界项 | 内容 |
| --- | --- |
| 外部使用者 | HWPOD工具、Agent编排、HarnessRL、客户端、用户管理、平台管理员。 |
| 外部输入 | HWPOD spec、node 心跳、能力上报、租约请求、操作请求、用户/任务上下文、释放请求和节点结果。 |
| 受控资源 | registry、资源状态、租约、路由表、操作请求、operation result 和错误分类。 |
| 外部输出 | 资源列表、健康状态、租约状态、路由结果、操作结果、错误语义和结果查询摘要。 |
| 用户接口 | HWLAB runtime API、HWPOD 服务端接口、工具调用接口和 CaseRun/Agent 消费接口。 |
| 系统边界 | HWPOD服务负责服务端硬件资源真相和路由归属；不定义 spec 字段、命令行体验、节点适配器内部实现或 Harness 评价。 |

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

| 编号 | 模块或课题 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
| --- | --- | --- | --- | --- | --- |
| PJ2026-01010301 | 资源注册 | 本规格 6.1 | registry、spec 摘要、authority 和资源状态 | HWPOD标准、平台配置 | 工具、客户端、Agent编排 |
| PJ2026-01010302 | 租约占用 | 本规格 6.2 | 租约、占用、释放、冲突处理和写操作保护 | 用户管理、资源注册 | Agent编排、CaseRun |
| PJ2026-01010303 | 节点路由 | 本规格 6.3 | 请求接收、目标解析、node 路由、超时和错误分类 | AI网关、租约占用 | HWPOD工具、HarnessRL |
| PJ2026-01010304 | 结果归属 | 本规格 6.4 | operation result 归属、查询和摘要交接 | 节点路由、Agent上下文 | HarnessRL、客户端、用户管理 |
| PJ2026-01010305 | 71FREQ预装 | [PJ2026-01010305 71FREQ预装](PJ2026-01010305-71freq-hwpod-v03-preinstall.md) | D601/v03 71-FREQ preinstalled HWPOD spec、运行发现、MDTODO source 和验收切片 | HWPOD标准、YAML运维、AI网关 | HWPOD工具、HarnessRL、客户端 |

## 6. 原子需求

### 6.1 HWPOD-SVC-REQ-001 资源注册

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| HWPOD-SVC-REQ-001 | 资源注册 | PJ2026-01010301 资源注册 | [PJ2026-010101 HWPOD标准](PJ2026-010101-hwpod-standard.md)、[客户端](PJ2026-0104-client.md) |

HWPOD服务应维护 HWPOD registry，使已声明资源、spec 摘要、authority、状态、能力和路由信息能够被工具、客户端和上层任务查询。

Registry 必须以 HWPOD 标准解释资源事实。缺失 HWPOD spec 的真实设备不能被服务端当作可写资源暴露；客户端可以展示不可用或待配置状态，但不能把临时端点当作资源真相。

Registry 必须区分两种 authority：

- `yaml-first-builtin` 来自 owning YAML 解析后注入的内置 spec，`mutable=false`、`frozen=true`；
- `runtime` 来自 owning YAML 声明的 host PostgreSQL，`mutable=true`、
  `frozen=false`，API、Worker、Pod 和 host 进程重启后继续可读。

Runtime repository 必须使用唯一 PostgreSQL authority：

- development 的 L0、L1 和 L2 共用同一个 host PostgreSQL database；
- production 的 L3 使用 production owning YAML 声明的 host PostgreSQL database；
- database、role、endpoint、TLS、Secret sourceRef、sourceKey 和 schema/table identity
  只能来自 owning YAML；
- runtime 表以 `hwpod_id` 为唯一键，保存规范化后的完整 `document JSONB`、
  固定 authority `runtime`、`created_at` 和 `updated_at`；
- repository 初始化只执行幂等 schema/table/index migration，不创建隐藏 database、
  role、凭据或 filesystem fallback；
- YAML-first 内置 spec 只在读取时与 PostgreSQL runtime 记录合并，
  不写入 runtime 表。

Runtime CRUD 只能修改 `runtime` authority：

- create 在 hwpodId 不存在时以唯一键约束和单条事务原子写入；
- get 和 list 合并返回内置与 runtime spec，并保留 authority、mutable 和 frozen；
- update 只能在单条事务中完整替换已有 runtime spec，并保留 `created_at`；
- delete 只能在单条事务中删除已有 runtime spec；
- 内置 spec 的同名 create、update 和 delete 均返回 `hwpod_spec_frozen`；
- runtime spec 不得遮蔽、覆盖、复制或回写 YAML-first 内置 spec。

filesystem JSON registry、runtime spec directory 参数和目录环境变量属于
`legacy-retire`。实现不得保留 filesystem fallback、双写、启动导入、overlay
或第二 authority；历史 JSON 只允许通过显式一次性迁移工具处理，不参与正常 CRUD。

### 6.2 HWPOD-SVC-REQ-002 租约与占用

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| HWPOD-SVC-REQ-002 | 租约占用 | PJ2026-01010302 租约占用 | [用户管理](PJ2026-0105-user-management.md)、[Agent编排](PJ2026-0102-agent-orchestration.md) |

HWPOD服务应提供租约、占用、释放、冲突处理和超时恢复能力，使真实硬件写操作不会被多个任务并发破坏。

租约只定义硬件资源占用事实。用户管理提供调用主体和权限约束，Agent编排提供任务上下文，HWPOD服务负责把这些约束落实到资源可用性和写操作保护。

CaseRun 触发的 build、download、reset、UART 或 workspace 写操作必须绑定明确 runId、caseId、hwpodId、nodeId、actor 和租约。相同 HWPOD 在已有写租约期间不得被另一条 Web CaseRun、CLI 诊断或旧 runner 静默复用；冲突必须作为可查询 blocker 返回给 HarnessRL 和客户端。

### 6.3 HWPOD-SVC-REQ-003 节点路由

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| HWPOD-SVC-REQ-003 | 节点路由 | PJ2026-01010303 节点路由 | [PJ2026-010104 AI网关](PJ2026-010104-ai-gateway.md)、[PJ2026-010102 HWPOD工具](PJ2026-010102-hwpod-tools.md) |

HWPOD服务应把已授权且租约一致的操作请求路由到正确 HWPOD node，并把目标不存在、node 离线、路由超时、协议连接失败和节点返回失败区分输出。

节点路由必须禁止错误 HWPOD 复用。工具请求某个 `hwpod-id` 时，服务端只能使用该资源声明绑定的 node 和能力；无法找到声明或路由时必须返回明确失败。

HWPOD 服务端只作为云端请求接收、租约校验、目标解析和网关路由 authority；Cloud Web、Agent 和 CLI 不应直接连接用户 PC 上的 gateway。网关主动出站后，服务端仍必须把命令领取、in-flight、超时、`gateway_busy` 和节点返回失败归一为可查询的 operation 状态，避免调用方把 HTTP dispatch timeout 误判为硬件动作结果。

Web CaseRun 的所有硬件动作都必须通过 HWPOD 服务节点路由。服务端应在 route 摘要中暴露目标 hwpodId、nodeId、声明 capability、node 上报 capability、route authority、request id 和必要 trace 关联，使 HarnessRL 能区分 workspace missing、node offline、capability mismatch、probe mismatch、gateway busy、adapter failure 和硬件动作失败。

### 6.4 HWPOD-SVC-REQ-004 结果归属

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| HWPOD-SVC-REQ-004 | 结果归属 | PJ2026-01010304 结果归属 | [HarnessRL](PJ2026-0103-harness-rl.md)、[客户端](PJ2026-0104-client.md)、[用户管理](PJ2026-0105-user-management.md) |

HWPOD服务应把每次 operation result 归属到明确的 HWPOD、node、租约、调用方、操作类型和时间上下文，使 HarnessRL、客户端和账务统计能消费同一结果事实。

结果归属不是长证据归档。服务端只负责保存和交接必要操作结果、摘要和查询指针；CaseRun 评价、回放、训练反馈和用户展示由对应模块在此事实上继续处理。

Web CaseRun 消费的 operation result 至少应能被 HarnessRL 引用到同一 run stage，并携带 op 类型、target path 或 probe 摘要、returnCode 或失败分类、日志/证据指针、valuesRedacted、requestId/trace 关联和 node-reported capability 摘要。HWPOD服务不生成 CaseRun aggregate，但必须提供足够稳定的 operation result 引用，使 aggregate、artifact manifest、Web run 卡和 web-probe report 指向同一硬件事实。

### 6.5 HWPOD-SVC-REQ-005 Topology Read Model

| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| HWPOD-SVC-REQ-005 | 拓扑投影 | PJ2026-01010301 资源注册、PJ2026-01010303 节点路由 | [AI网关](PJ2026-010104-ai-gateway.md)、[云端控制台](PJ2026-010405-cloud-console.md) |

HWPOD服务应提供有界 typed topology read model，统一表达 owning 配置声明但离线的 node、已连接 node、在线但未挂 spec 的 node、node 下零到多个 HWPOD、声明/实际 capability、in-flight、busy、最近 operation 和诊断摘要。

该投影必须分别表达 service ready、node online、HWPOD available、leased/busy 和 capability mismatch。列表接口只返回有界摘要并支持服务端筛选、排序和 cursor；完整 spec document、日志和诊断通过实体详情或专用查询渐进披露。

Cloud API 可以代理并映射主体、ACL、错误与 correlation，但不得在浏览器或 Cloud API 临时拼装第二份 topology authority。若连接规模要求抽取独立 HWPOD 服务，registry、topology、operation 和诊断事实必须随 owner 一次迁移。

## 7. 独立服务架构与运行等级

HWPOD 服务应作为独立的可组合应用交付，分为 Temporal worker、API 后端和 Web 前端三个可独立启动、停止、检查和扩缩的运行单元。

### 7.1 目标架构

```mermaid
flowchart LR
  W[HWPOD Web] --> A[HWPOD API]
  C[HWPOD CLI / Cloud API] --> A
  A --> T[Temporal namespace unidesk]
  T --> WK[HWPOD Worker]
  WK --> R[Registry / Operation ledger]
  WK --> N[主动出站 HWPOD Node]
  N --> H[真实硬件与工作区]
```

- API 只负责 HTTP envelope、鉴权、correlation、查询投影和 workflow 提交。
- Worker 负责 HWPOD workflow、节点路由、operation 状态推进和结果归属。
- Web 只依赖 HWPOD API 合同，不复制 registry、topology 或 operation authority。
- Cloud API 可以代理 HWPOD API，但不得在 Cloud API 内保留第二份 HWPOD 业务 authority。
- HWPOD Node 通过主动出站连接注册到服务端入口；节点不得依赖用户侧公网入站端口。

### 7.2 L0/L1 合同

- L0 必须能在不启动 API、worker、Temporal、Web 或 Kubernetes workload 的情况下，直接验证 spec 解析、topology 投影、workflow 输入和错误分类。
- L1 必须能按 owning YAML 独立启动 API、worker 和 Web，并用同一 HWPOD API 合同完成健康、spec、topology、operation 和 workflow smoke。
- L1 API 与 Web 验收使用 owning YAML 声明的 native host 和固定端口；公网域名、TLS、public-edge、CI/CD 和 Kubernetes 不进入 L1 完成条件。
- L1 API、worker 和 Web 必须分别暴露健康/就绪检查；worker 不得创建公网业务入口。
- L1 Web 必须支持 HWPOD 资源列表、节点状态、operation 状态和明确 blocker 展示，且页面刷新后仍通过 API 恢复同一投影。

### 7.3 稳定接口

- `GET /health/live` 和 `GET /health/ready`：分别返回进程存活和 HWPOD/Temporal 依赖就绪状态。
- `GET /v1/hwpod/specs`：返回有界 HWPOD spec 摘要和可用性。
- `GET /v1/hwpod/specs/{hwpodId}`：返回单个完整 spec document 与 authority。
- `POST /v1/hwpod/specs`：创建 runtime spec。
- `PUT /v1/hwpod/specs/{hwpodId}`：完整替换 runtime spec。
- `DELETE /v1/hwpod/specs/{hwpodId}`：删除 runtime spec。
- `GET /v1/hwpod/topology`：返回 node、HWPOD、能力、占用、最近 operation 和 blocker 投影。
- `POST /v1/hwpod/operations`：提交带有 `operationId`、`hwpodId`、`nodeId`、调用方和租约摘要的 workflow。
- `GET /v1/hwpod/operations/{operationId}`：读取同一 operation 的 durable 状态和结果摘要。

所有接口必须保持 `valuesPrinted=false`，不得返回 token、Authorization、Secret 值或可复用节点凭据。

### 7.4 验收契约

- L0：spec、topology、workflow contract 和 typed error 测试通过；runtime CRUD
  直接修改 owning YAML 选择的 development host PostgreSQL，内置 spec mutation
  返回 `hwpod_spec_frozen`。
- L0/L1：对同一 runtime spec 做 `--local` 与 `--over-api` 对比复测，
  两条路径返回一致的 document、authority 和 fingerprint。
- L1：通过 native API 完成 runtime spec create、list、get、update、delete，
  并证明 API 重启后 create/update 结果仍可读取。
- L2：development API 完成同一 CRUD，并证明 Deployment/Pod 重启后记录仍可读取；
  该验证不得使用 Pod filesystem 作为持久化证据。
- L3：完成 L2 回归并取得本次生产操作明确授权后，production API 完成有界 CRUD
  和 Pod 重启持久化验证；测试对象必须清理，内置对象指纹保持不变。
- L1：对 YAML-first 内置 spec 的同名 create、update 和 delete 均返回 `hwpod_spec_frozen`，内置 document 指纹保持不变。
- L1：API、worker、Web 可分别重启；worker 重启后未完成 workflow 可继续；Web 通过固定入口完成首屏、资源列表和 operation 状态交互。
- L1：D601 节点注册后，HWPOD topology 同时显示 node online、spec available 和 capability match；节点断开后显示 node offline，不得伪造硬件成功。
- L1：Cloud API 代理、独立 HWPOD API 和 CLI 对同一 operation 返回相同的 operation identity、状态和 blocker code。
