25 KiB
Device Pod 迁移对照规格
本文保留 HWLAB v0.2 既有 device-pod 正式接入口径,作为 HWPOD Harness 迁移对照。新的 HWPOD 业务方向以 spec-hwpod-harness.md 和 pikasTech/HWLAB#897 为准:快速迭代阶段先把 hwpod-spec、hwpod-cli、hwpod-ctl 和 hwpod-compiler-cli 放在 Code Agent workspace 内,hwlab-api 只做 hwpod-node-ops 转发,hwpod-node 只维护少量稳定 ops。
旧 device-pod 是一个逻辑设备能力单元,不是 Kubernetes Pod 名称,也不是 HWPOD 目标状态下的产品主概念。旧 profile/server authority 路径仍可用于现有 v0.2 兼容和迁移对照,但新增业务翻译应优先进入 hwpod-compiler-cli,不要继续堆在 hwlab-device-pod executor 或 device-host-cli.mjs 中。
实施跟踪见 pikasTech/HWLAB#533,原 docs/plan/v02-device-pod-spec-migration.md 和旧 device-pod MVP 计划全文已迁入该 issue 评论。
旧的 device-pod-cli 本地 profile 闭环只用于 CLI MVP 和真实硬件最小验证。既有正式多用户 device-pod 路径曾收敛到:
browser Cloud Web UI or hwpod/device-pod-cli
-> cloud-api AuthPrincipal + OpenFGA relation check
-> hwlab-device-pod internal REST
-> gateway transport
-> device-host-cli
-> Keil / pyOCD / UART / target
AgentRun runner 和 hwpod 的标准设备 API 入口是 HWLAB_RUNTIME_API_URL=http://hwlab-cloud-api.<namespace>.svc.cluster.local:6667,不是 hwlab-cloud-web。Cloud Web 只服务浏览器同源 UI 代理;hwpod 必须携带映射到发起用户的 HWLAB_API_KEY 直连 cloud-api,由 cloud-api 按该用户 grant 授权。内部 :6667 属于 WHATWG bad port 时,hwpod 必须使用 Node http/https 原生请求层访问 cloud-api,不能为了规避 bad-port 把设备 API 改走 Cloud Web。
在系统中的职责划分
device-pod 是云端可授权、可审计的逻辑设备能力单元。hwlab-cloud-api 是用户身份、用户 API key、grant、profile authority 和用户态 REST API 的入口;hwlab-device-pod 是内部执行服务;hwlab-gateway 只承载 transport;device-host-cli 只在硬件 host 侧执行 Keil、pyOCD、UART 和 workspace 操作。
普通用户、浏览器和 Code Agent session 不直接持有 gateway route、host workspace route、Kubernetes Service 直连能力或 profile 修改权。
设计目标
- 用最少组件把
device-pod-cli从“本地 profile + RPC/gateway 调用”迁到“1:1 REST 请求”。 cloud-api是用户身份、用户 API key、OpenFGA relation 和 profile authority 判断入口。hwlab-device-pod承接设备业务:profile 校验后的运行、job 生命周期、freshness、blocker、bounded output 和 gateway 调用。device-pod-cli只做 selector 解析、cloud-api REST 请求和 JSON 输出;默认正式模式不读取.device-pod/*.json,不保存、不上传、不修改权威 profile。- 第一阶段只部署一个
hwlab-device-podDeployment/Service,管理多个逻辑devicePodId,避免为每台设备创建独立 k8s Service/Deployment。 - 普通用户和 code agent session 不获得 Kubernetes 用户、Service 直连权限、gateway route 或 host workspace route。
逻辑模型
一个 device-pod 由四个设备能力要素组成:
device-pod
= deviceTarget
+ debugInterface
+ projectWorkspace
+ ioInterface
deviceTarget:被测设备目标,例如开发板、用户 PCB 或仪器模块。debugInterface:下载、复位、chip-id、probe 状态和调试连接能力。projectWorkspace:源码、工程、构建工具链和 artifact 边界。ioInterface:UART、DI/DO、采样、日志和其他设备 I/O 观测/控制能力。
devicePodId 是云端和用户界面的稳定身份。实际 k8s Pod 可以重建、滚动或扩容;用户和 code agent 不依赖实际 Pod name。
Profile Authority
正式接入后,profile 是管理员侧资源:
admin UI/API
-> cloud-api
-> device_pods.profile_json + profile_hash
-> hwlab-device-pod internal execution
code agent 本地文件只能作为非权威 hint/cache,最多包含:
{
"devicePodId": "device-pod-71-freq",
"profileHash": "sha256:...",
"cloudApiUrl": "..."
}
本地 hint/cache 不得包含以下字段,也不得参与授权或执行路由:
gatewaySessionIdresourceIdcapabilityIdhostWorkspaceRoothostCli- Windows workspace 路径
- probe UID、串口端口、Keil 路径等硬件路由字段
正式 profile 必须由 cloud-api 从 DB 读取;hwlab-device-pod 不接受浏览器、code agent 或 CLI 上传的 profile 作为执行依据。若 hwlab-device-pod 需要 profile snapshot,应只接受 cloud-api 内部服务凭据转发的 snapshot,或通过内部服务凭据向 cloud-api 拉取。该凭据不得挂载进 code agent session Pod。
内部架构
正式 device-pod 由 profile registry、job lifecycle、freshness/blocker、bounded output、gateway/device-host adapter 和用户 API key integration 组成。第一阶段只有一个 hwlab-device-pod Deployment 管理多个 devicePodId;profile authority、OpenFGA relation 和 api_keys 在 cloud-api/Postgres 中,device-pod 服务只接受 cloud-api 内部调用。
当前 v02 部署中的 hwlab-device-pod 微服务实现情况见 spec-v02-hwlab-device-pod-service.md。
Profile Shape
device_pods.profile_json 至少表达以下 server-side 字段:
{
"schemaVersion": 1,
"devicePodId": "device-pod-71-freq",
"target": {
"id": "target-id"
},
"projectWorkspace": {
"workspaceRoot": "F:\\Work\\Project",
"projectPath": "FirmWare/MDK-ARM/app.uvprojx",
"targetName": "app",
"hexPath": "FirmWare/MDK-ARM/app/app.hex"
},
"debugInterface": {
"type": "cmsis-dap",
"probeUid": "...",
"uv4Path": "C:\\Keil_v5\\UV4\\UV4.exe"
},
"ioInterface": {
"uart": [
{ "id": "uart/1", "port": "COM4", "baudRate": 921600 }
]
},
"route": {
"gatewaySessionId": "gws_...",
"resourceId": "res_...",
"capabilityId": "cap_...",
"hostWorkspaceRoot": "F:\\Work\\Project",
"hostCli": "node tools\\device-host-cli.mjs"
}
}
profile_json 不得保存 Git key、云 token、kubeconfig、数据库 URL 或长期 secret。profile_hash 由 cloud-api 对规范化 profile JSON 计算并在所有响应中返回;用户可见响应只能返回脱敏 profile 摘要和 hash。
数据表口径
正式规格推荐 device_pods 直接保存权威 profile 和 hash,避免额外 profile 微服务:
CREATE TABLE IF NOT EXISTS device_pods (
id TEXT PRIMARY KEY,
name TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
profile_json TEXT NOT NULL DEFAULT '{}',
profile_hash TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
历史版本中的 profile_ref、gateway_ref 或 device_pod_json 可以在迁移时折叠进 profile_json。第一阶段不新增 device_pod_profile_revisions;需要审计版本、回滚或多环境批准时再引入 profile revision 表。
历史版本中的 device_pod_grants 不是当前 v0.2 device pod 授权契约。目标状态的 device pod 可见、操作、profile 修改和 job 提交权限只由 OpenFGA relation 表达;旧表若仍存在于已发布数据库中,只能作为历史迁移输入,不得作为写入口、健康必需表或 allow 判定来源。
REST API
API 接口说明
用户态 API 只经过 cloud-api 暴露:
GET /v1/device-pods
GET /v1/device-pods/{devicePodId}/status
GET /v1/device-pods/{devicePodId}/debug-probe/chip-id
GET /v1/device-pods/{devicePodId}/io-probe/uart/1
GET /v1/device-pods/{devicePodId}/io-probe/uart/1/tail?maxBytes=12000
POST /v1/device-pods/{devicePodId}/jobs
GET /v1/device-pods/{devicePodId}/jobs/{jobId}
GET /v1/device-pods/{devicePodId}/jobs/{jobId}/output
POST /v1/device-pods/{devicePodId}/jobs/{jobId}/cancel
管理员 API 由 cloud-api 提供:
POST /v1/admin/device-pods
PUT /v1/admin/device-pods/{devicePodId}
PUT /v1/admin/access/users/{userId}/device-pods/{devicePodId}/{relation}
DELETE /v1/admin/access/users/{userId}/device-pods/{devicePodId}/{relation}
POST /v1/device-pods/{devicePodId}/jobs 用 intent 表达具体业务,避免把 REST surface 扩张成大量一次性 route:
{
"intent": "workspace.build",
"args": { "profile": "debug" },
"reason": "DEV smoke"
}
第一阶段 intent 集合:
workspace.lsworkspace.bootsharpworkspace.catworkspace.rgworkspace.apply-patchworkspace.putworkspace.rmworkspace.rmdirworkspace.keilworkspace.builddebug.statusdebug.chip-iddebug.downloaddebug.resetio.portsio.uart.readio.uart.read-after-launch-flashio.uart.writeio.uart.jsonrpc
GET /debug-probe/chip-id、GET /io-probe/uart/1 和 GET /io-probe/uart/1/tail 是用户态便捷 REST surface,但不能停留在静态面板或 fake probe;cloud-api 必须在完成 authenticate/grant 后创建对应只读 job,再经 hwlab-device-pod executor/gateway/device-host-cli 执行或返回同一套 blocker。
所有 job/status/output 和 probe GET 响应必须包含 devicePodId、targetId、profileHash、traceId、operationId、status、freshness、blocker 和 bounded output metadata。job output 文本默认最大 12000 bytes;超出时必须设置 truncation.truncated=true、truncation.originalBytes,并避免把完整 executor/gateway 原始输出嵌回 JSON。真实硬件响应不得把 fake、dry-run、SOURCE、LOCAL 或过期缓存标为 DEV-LIVE。
微服务职责
| 服务 | 职责 |
|---|---|
hwlab-cloud-api |
用户身份、admin/user、用户 API key、OpenFGA relation、profile authority、用户态 REST API、转发到内部 device-pod。 |
hwlab-device-pod |
多 devicePodId 运行 registry、profile runtime validation、job store、freshness、bounded output、gateway/device-host-cli adapter。 |
device-pod-cli |
把 devicePodId:surface:path operation args 1:1 转成 cloud-api REST;不保存权威 profile、不读取本地 profile 作为默认 authority、不直连 gateway。 |
device-host-cli |
Windows host 侧自包含业务工具,负责 Keil、pyOCD、UART、workspace 文件操作。 |
hwlab-gateway |
只做受控 transport,不理解用户权限和 device-pod 授权。 |
hwlab-cloud-web |
展示用户可见 device pod、admin 管理 profile/relation、显示 job/status/freshness。 |
Kubernetes 口径
v0.2 第一阶段使用一个 hwlab-device-pod Deployment 和一个 ClusterIP Service:
hwlab-v02/hwlab-device-pod
replicas: 1
manages: many devicePodId
不为每个 devicePodId 创建 Deployment、Service、Ingress、Secret 或 namespace。这样更符合当前规模:运维对象少、GitOps diff 少、问题定位简单,也不会把设备数量直接放大成 k8s 资源数量。
只有在满足以下条件时,才考虑拆分为多个 hwlab-device-pod shard 或 per-device workload:
- 单个服务内 job 队列和 freshness 监控互相影响;
- 不同设备需要不同 host network、USB、Secret 或资源 request;
- 设备数量增长到单实例状态管理明显吃力;
- 强隔离需求超过应用层 OpenFGA relation 和内部服务凭据能覆盖的范围。
普通用户和 code agent session Pod 不应直接调用 hwlab-device-pod Service。正式路径是 code agent -> cloud-api -> hwlab-device-pod。
验收标准
device-pod-cli在正式模式下不读取.device-pod/<devicePodId>.json作为权威 profile,只向 cloud-api 提交devicePodId、intent 和 args。- 普通用户无授权时不能看到或使用任何 device pod;拥有
viewer只能看到摘要,拥有operator/job_submitter才能提交对应 job,拥有profile_editor才能修改 profile。 - code agent 不能通过修改本地文件改变 gateway session、resource、host workspace、probe UID 或 UART port。
hwlab-device-pod不接受无内部服务凭据的 profile snapshot 或 job 请求。hwlab-device-pod一个实例可以列出并执行多个devicePodId的状态/job。- cloud-api legacy compatibility entry 只能返回 blocked authority payload,不得合成 fake device pod 数据或作为正式 device-pod DEV-LIVE 证据。
- 强副作用 job 必须有
reason;正式路径只使用 Web session/cookie 或映射到具体用户的HWLAB_API_KEY做身份授权。 - AgentRun runner 访问 device-pod 必须使用 cloud-api 组装的用户
HWLAB_API_KEY,该 key 恢复为发起 Code Agent session 的 owner 用户;不得使用跨用户共享、对所有正式 device-pod 授权的 system key。 - 撤销 device pod relation 必须同时影响该用户通过 Web session、CLI API key 和 AgentRun
hwpod的可见性与使用权;revoke API key 后 CLI 和 runner 内旧 key 都必须失效。
CLI 实现口径
tools/device-pod-cli.ts 是 v0.2 正式 CLI 实现;HWLAB code-agent runner 内的唯一稳定短入口是 hwpod。runner 镜像必须把 hwpod 放入 PATH;缺少 hwpod 时应判定为 runner image/package 错误并修复镜像或封装,不得改走 /app/skills/device-pod-cli/scripts/device-pod-cli.mjs 长路径。正式 CLI 的默认行为是:
profile list/show调用 cloud-api/v1/device-pods和/status,只显示服务端脱敏 profile 摘要和profileHash。- AgentRun runner 中只使用装配好的
HWLAB_RUNTIME_API_URL和映射到当前用户的HWLAB_API_KEY,直接访问hwlab-cloud-api;不得手动传--api-base-url,也不得改走 Cloud Web 同源代理。 setup first-admin和admin device-pod upsert只作为 cloud-api REST wrapper,用于首次空库 seed 或 admin profile 管理;device pod 授权统一使用hwlab-cli client access device-pods grant/revoke的 Admin Access API,不走hwpod admin grant。devicePodId:workspace|debug-probe|io-probe...selector 转换为POST /v1/device-pods/{devicePodId}/jobs或 job status/output/cancel REST,不直接调用/v1/rpc/hardware.invoke.shell。bootsharp --pod-id <devicePodId>和<devicePodId>:workspace:/ bootsharp都转换为workspace.bootsharpjob,用于返回 workspace tree、AGENTS.md 摘要和当前路径提示;该入口是上下文恢复和 DS 派单的首个探测动作,不读取本地 profile。- workspace 写操作覆盖
apply-patch、put、rm、rmdir、build和keil add-source/remove-source等 Keil 工程维护动作。 - 源码局部编辑优先使用
apply-patch;put只用于明确的整文件写入或新文件创建。 - UART 业务覆盖
read、write、read-after-launch-flash和jsonrpc;JSON-RPC 请求必须由 device-host-cli 校验 response id,除非显式传入允许 id mismatch 的业务参数。 - apply-patch 类失败必须返回可定位的 patch hint,例如缺少
*** End Patch、hunk 上下文不匹配或 header 错误;调用方应先重新读取目标文件再重试小 hunk,不应默认绕到整文件覆盖。 - mutating job 由 cloud-api 侧强制
reason;CLI 只转发intent、args和reason。 profile create这类本地 profile bootstrap 在正式默认路径中返回legacy_profile_create_removed;管理员应使用 cloud-api admin API 管理服务端 profile,并使用 Admin Access API 管理 relation。- DS/device-pod prompt 和 skill 示例必须优先使用
hwpod,避免把长路径 wrapper 复制成常态命令;host job 轮询时 job id 必须作为status/output/cancel的紧随位置参数传入,不能放到 flags 后面或靠 shell 管道解析 JSON。
D601 F103 v0.2 Gateway SOP
D601 Windows F103 gateway 的稳定命名使用 gws_D601_F103。不要因为当前 devicePodId 或样例设备名是 device-pod-71-freq / 71-FREQ,把 gateway session 改成旧的 gws_d601_win_71_freq;profile route 和 Windows gateway 运行脚本必须使用同一组 F103 命名。
当前正式接入的 F103 v2 逻辑设备名为 D601-F103-V2。它的 Windows workspace 固定为 F:\Work\D601-HWLAB,Keil 工程为 projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx,Keil target 为 USART,Keil 可执行文件为 C:\Keil_v5\UV4\UV4.exe,UART 为 COM9/115200。v0.2 服务端 profile 必须使用 devicePodId=D601-F103-V2,不得继续把该 workspace 暴露成 device-pod-71-freq。
Windows 侧固定入口:
Task Scheduler: HWLAB-DevicePodGateway-D601-F103
run script: C:\Users\liang\device-pod-gateway-rust\run-D601-F103.cmd
local status: http://127.0.0.1:7001/status
cloud API: http://74.48.78.17:19667
run-D601-F103.cmd 中的关键环境变量应保持为:
set "HWLAB_GATEWAY_CLOUD_URL=http://74.48.78.17:19667"
set "HWLAB_ENVIRONMENT=v02"
set "HWLAB_GATEWAY_ID=gtw_D601_F103"
set "HWLAB_GATEWAY_SESSION_ID=gws_D601_F103"
set "HWLAB_GATEWAY_RESOURCE_ID=res_windows_host"
set "HWLAB_GATEWAY_BOX_ID=box_windows_host"
set "HWLAB_GATEWAY_CMD_CAPABILITY_ID=cap_windows_cmd_exec"
set "HWLAB_GATEWAY_CMD_EXEC_ENABLED=1"
set "HWLAB_GATEWAY_MAX_INFLIGHT=4"
set "HWLAB_GATEWAY_CMD_TIMEOUT_MS=120000"
set "HWLAB_GATEWAY_PORT=7001"
v0.2 D601-F103-V2 的服务端 profile route 必须和 gateway 注册保持一致:
{
"gatewaySessionId": "gws_D601_F103",
"resourceId": "res_windows_host",
"capabilityId": "cap_windows_cmd_exec",
"hostWorkspaceRoot": "F:\\Work\\D601-HWLAB",
"hostCli": "node tools\\device-host-cli.mjs"
}
重启 gateway 时使用计划任务,不从临时 shell 直接启动长期进程:
schtasks /End /TN HWLAB-DevicePodGateway-D601-F103
schtasks /Run /TN HWLAB-DevicePodGateway-D601-F103
powershell -NoProfile -Command "Invoke-RestMethod http://127.0.0.1:7001/status | ConvertTo-Json -Depth 12"
通过 UniDesk Windows route 操作时,工作目录应直接定位到 gateway 目录,例如 D601:win/c/Users/liang/device-pod-gateway-rust,再读取 run-D601-F103.cmd 或查询 /status。/status 中至少应看到 gatewaySessionId=gws_D601_F103、cloudUrl=http://74.48.78.17:19667、session.status=connected、outbound.lastPollError=null。
G14 v0.2 验收在 G14:/root/hwlab-v02 执行,先确认 Cloud Web 同源 CLI 能看到 device pod 状态,再用正式 device-pod-cli 创建并轮询 job:
bun tools/hwlab-cli/bin/hwlab-cli.ts client device-pods status device-pod-71-freq \
--base-url http://74.48.78.17:19666 \
--full
COOKIE=$(node -pe 'require("./.state/hwlab-cli/session.json").cookie')
bun tools/device-pod-cli.ts device-pod-71-freq:workspace:/ ls \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE" \
--reason "v02 gws_D601_F103 smoke" \
--timeout-ms 120000 | tee /tmp/hwlab-device-pod-job.json
JOB=$(node -e 'const fs=require("fs"); const payload=JSON.parse(fs.readFileSync("/tmp/hwlab-device-pod-job.json", "utf8")); console.log(payload.body.job.id)')
bun tools/device-pod-cli.ts job status --pod-id device-pod-71-freq "$JOB" \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE"
bun tools/device-pod-cli.ts job output --pod-id device-pod-71-freq "$JOB" \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE"
D601-F103-V2 的验收命令使用同一条 v0.2 CLI 链路,只替换 devicePodId 并从 bootsharp 开始:
bun tools/hwlab-cli/bin/hwlab-cli.ts client device-pods status D601-F103-V2 \
--base-url http://74.48.78.17:19666 \
--full
COOKIE=$(node -pe 'require("./.state/hwlab-cli/session.json").cookie')
bun tools/device-pod-cli.ts bootsharp --pod-id D601-F103-V2 \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE"
bun tools/device-pod-cli.ts D601-F103-V2:workspace:/ build start \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE" \
--reason "D601-F103-V2 Keil build validation" \
--timeout-ms 120000
bun tools/device-pod-cli.ts D601-F103-V2:debug-probe download start \
--api-base-url http://74.48.78.17:19667 \
--cookie "$COOKIE" \
--reason "D601-F103-V2 Keil download validation" \
--capture-uart uart/1 \
--capture-duration-ms 8000 \
--timeout-ms 120000
Code-agent/DS runner 内执行同类验收时,把 bun tools/device-pod-cli.ts 换成 hwpod;hwpod 不在 PATH 时应判定为 runner 镜像或包安装错误并修复该标准入口,不得临时改走长路径 wrapper。UART 串口若被 Windows 侧工具占用,应把 COM busy/access denied 记录为可选串口证据缺口,Keil build/download 是否通过以 job output 中的 build summary、Programming Done、Verify OK 和 Application running 为准。
DS 或其他 code-agent runner 由 hwlab-cli client harness submit 触发时,控制面应保持短连接:提交后用 client harness result、client harness trace --limit <N> 和 client harness audit --require-bootsharp 轮询,不把 UniDesk ssh/tran 连接长期挂在一次 wait 上。client harness wait 只用于短窗口观察,CLI 会把超长等待压到低于 UniDesk 透传硬超时的安全窗口,并在 JSON 中返回后续短轮询命令。
job 观察优先使用 cloud-api job 入口,避免从 shell 管道里解析整段 JSON:
hwpod job status --pod-id D601-F103-V2 <jobId> --api-base-url <url> --cookie "$COOKIE"
hwpod job output --pod-id D601-F103-V2 <jobId> --api-base-url <url> --cookie "$COOKIE"
build status/output/cancel <jobId> 和 download status/output/cancel <jobId> 只作为 selector 便捷别名;当 <jobId> 是 job_devicepod_* 这类 cloud-api job 时,别名必须映射到 /jobs/<jobId> 或 /jobs/<jobId>/output,不得误启动新的 build/download job。Keil host 侧子 job 仍保留 build status <hostJobId> 或 download status <hostJobId> 语义,用于查看 Windows device-host-cli 创建的嵌套 job。
搜索下载、烧录或串口证据时,带空格、管道符或较长正则的 workspace rg 应使用显式参数,避免本地 shell、selector 和 Windows host 三层参数解析产生歧义:
hwpod D601-F103-V2:workspace:/ rg \
--pattern "Programming Done|Verify OK|Application running|Error" \
--path projects/01_baseline/captures \
--api-base-url <url> --cookie "$COOKIE"
验收通过条件:client device-pods status 返回 status=ok 且 blocker=null;gateway sessions 中 gws_D601_F103 为 online;device-pod-cli job 进入 completed,且 D601 Windows gateway /status.lastDispatch.operationId 与该 job 的 operationId 一致并有 lastResultAt。旧 gws_d601_win_71_freq session 只能作为历史 stale 线索,不能作为 v0.2 F103 gateway 的目标命名。
测试规格
T1
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:普通用户无 grant 时访问 /v1/device-pods 不得看到任何 device pod;获得 grant 后能看到对应 devicePodId 和脱敏 profileHash,不能看到 gatewaySessionId、hostWorkspaceRoot 或 probe UID 等敏感路由字段。
T2
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:尝试通过本地 .device-pod/*.json 修改 gateway route 或 workspace route,正式 cloud-api/device-pod 路径必须忽略该本地文件并继续使用服务端 profile authority。
T3
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:提交一个强副作用 job,例如 download/reset,缺少 reason 时必须被拒绝;补充 reason 后必须经同一条 cloud-api job REST 路径进入 executor,并返回 devicePodId、profileHash、traceId、operationId、freshness、blocker 和 bounded output metadata。
T4
阅读 docs/reference/spec-device-pod.md,然后用 cli 手动测试以下内容:对授权 Device Pod 运行 workspace put、workspace rm、workspace rmdir、workspace keil add-source/remove-source 和 io-probe jsonrpc 的 --dry-run 与一次真实小闭环。确认请求只经过 cloud-api job REST,输出 intent、reason、traceId 和 bounded output,不读取本地 profile、不直连 gateway。
规格的实现情况
| 规格项 | 状态 | 说明 |
|---|---|---|
| 逻辑 device-pod 模型 | 已实现为规格 | 四要素、profile shape 和 Kubernetes 口径已定义。 |
| profile server authority | 部分实现 | cloud-api 保存正式 DB profile 并向用户返回脱敏摘要;device-pod executor 不接受用户上传 profile。 |
| 用户 relation + 用户 API key | 部分实现 | cloud-api 已实现 Admin Access relation、可见性过滤和强副作用 job reason 校验;AgentRun/hwpod 仍需从旧 shared device-pod key 收敛到映射用户的 HWLAB_API_KEY。 |
| REST/job API | 部分实现 | cloud-api 已实现 list/status/events/probe/job/output/cancel,并可把已授权 job 转发给内部 hwlab-device-pod executor;executor 已实现内部 job create/get/output/cancel lifecycle 和 gateway/device-host-cli dispatch adapter,无在线 gateway/device-host-cli 时返回 blocker。 |
| G14 device-host 功能吸收 | 部分实现 | v0.2 job intent 已覆盖 workspace put/rm/rmdir、Keil 工程维护和 UART JSON-RPC,保持 cloud-api profile authority、OpenFGA relation 和用户 API key runtime auth。 |
| 禁止 fake 作为 DEV-LIVE | 已实现/持续约束 | 规格和服务 payload 要求显式标记 fake/source。 |