# HWPOD Harness 规格

> **hwpod-node 运维操作见 `hwpod-ops` skill**（`~/.agents/skills/hwpod-ops/SKILL.md`），包含 G14 serve 模式、D601 Windows connect 模式启停、cloud-api 注册状态检查、源码同步、日志路径和故障排查。

本文是 HWLAB `v0.2` 的 HWPOD Harness 长期规格。概念体系和实施跟踪见 [pikasTech/HWLAB#897](https://github.com/pikasTech/HWLAB/issues/897)；HWPOD 集中服务式管理和 `hwpod-id` source-of-truth 收敛见 [pikasTech/HWLAB#1043](https://github.com/pikasTech/HWLAB/issues/1043)。当前实现只打通单线程核心业务闭环，不把鉴权、安全、并发、计量、复杂调度或 Evidence 体系作为前置条件。

本规格不保留旧设备执行路径作为迁移对照；新任务只按 HWPOD 单通道实现和验收。

## 默认运行通道

当前 Code Agent / CaseRun runner 的默认 HWPOD 合同是 `hwpod-id` 加本次任务的 workspace binding，不再要求 runner workspace 预装 `.hwlab/hwpod-spec.yaml`：

```text
Code Agent workspace
  hwpod-cli
  hwpod-ctl
  hwpod-compiler-cli
  task context: hwpodId + workspacePath

hwpod-cli / hwpod-ctl
  -> runtime HWPOD registry (/v1/hwpod/specs?hwpodId=...)
    -> HWPOD document + run workspace override
  -> hwpod-compiler-cli / in-process compiler
    -> hwpod-node-ops plan
      -> hwlab-api
        -> hwpod-node
```

核心边界：

- `hwpod-id` 是 WebUI、CLI、CaseRun、Code Agent 和 runner 的默认运行时引用。
- HWPOD 定义由 runtime service 解析；runner-local YAML 只作为显式 debug/import/export，不作为默认合同。
- `hwpod-cli` 是用户和 Code Agent 执行研发动作的入口。
- `hwpod-ctl` 是和 `hwpod-cli` 平级的管理入口，用于校验 `hwpod-id` 解析结果、检查四要素/node binding，以及 smoke/node 状态类操作。
- `hwpod-compiler-cli` / in-process compiler 把高层 intent 和 runtime-resolved HWPOD document 编译为 `hwpod-node-ops`。
- `hwlab-api` 只接收 `hwpod-node-ops` plan，负责转发和返回结果，不承担业务翻译。
- `hwpod-node` 是靠近硬件的薄执行节点，只维护少量稳定 op handler，不保存完整 `hwpod-spec`，也不解释高层 hwpod intent。

## 云端平台阶段

完整服务式 registry/source-of-truth 仍按 #1043 收敛；当前已具备最小 discovery/resolve 能力：

- `GET /v1/hwpod/specs` 可列出已知 HWPOD，并可按 `hwpodId` 查询用于 CLI/runner resolve。
- `hwpod-ctl spec validate --hwpod-id <id> --workspace-path <run-worktree>` 校验 runtime-resolved document 和四要素。
- `hwpod-cli ... --hwpod-id <id> --workspace-path <run-worktree>` 生成并提交 node-ops plan。
- 将本地 YAML 文件管理降级为显式导入、导出和调试能力，不再作为 AgentRun runner 默认合同。
- 将 `hwpod-compiler-cli` 服务化为云端 `hwpod-compiler`，供 Web、Code Agent、batch harness 和 CI/HIL gate 共用。
- 将 `hwlab-api` 从薄转发面扩展为 hwpod run 管理面，承载 run 状态、计划版本、结果归档和后续 Evidence。
- 只在多个任务反复需要同一类基础动作时扩展 `hwpod-node-ops`，避免把业务变化下沉到 node。

## 核心概念

| 概念 | 定义 | 当前阶段含义 |
| --- | --- | --- |
| `hwpod` | 硬件研发执行逻辑实体 | 由 target device、workspace、debug probe、io probe 四要素组成 |
| `hwpod-spec` | hwpod 的声明式定义 | 由 runtime service 解析；本地 YAML 仅用于显式 debug/import/export |
| `hwpod-cli` | 用户和 Code Agent 的任务入口 | 发起 inspect、workspace、build、download、reset、UART、JSON-RPC 和 closeout |
| `hwpod-ctl` | HWPOD 管理入口 | 检查 `hwpod-id`、四要素、node binding、执行 smoke 和临时维护动作 |
| `hwpod-compiler-cli` | HWPOD 编译器 | 把高层 intent + resolved document 编译为 `hwpod-node-ops` plan |
| `hwpod-compiler` | 云端化后的编译服务 | 由 `hwpod-compiler-cli` 成熟后服务化而来 |
| `hwpod-node-ops` | node 最小操作协议 | `hwlab-api` 和 `hwpod-node` 之间的稳定执行契约 |
| `hwpod-node` | 靠近硬件的薄执行节点 | PC host、AI 网关、调试器边缘设备或实验室控制盒上的 executor |
| `hwlab-api` | HWPOD node-ops 转发面 | 快速阶段只转发 node-ops plan 并返回 result |

`hwpod` 的四个本体要素固定为：

- target device：被研发或调试的目标设备。
- workspace：项目源码、工程、构建工具链和 artifact 边界。
- debug probe：下载、复位、chip-id、调试连接等能力。
- io probe：UART、JSON-RPC、GPIO/relay 或其他 I/O 观测与交互能力。

`nodeBinding` 是 `hwpod-spec` 的部署字段，不属于 hwpod 四个本体要素。

## HWPOD identity and document

默认入口通过 `--hwpod-id <id>` 解析 HWPOD document。`--workspace-path <run-worktree>` 是 CaseRun/单步调试绑定本次 subject worktree 的运行时 override。`--spec <path>` 只保留为显式 debug/import/export path，不允许作为 Code Agent runner 缺少 service resolve 时的 fallback。

第一版 HWPOD document 保持轻量：

```yaml
apiVersion: hwlab.dev/v0alpha1
kind: Hwpod
metadata:
  uid: hwpod-local-demo
  name: demo
spec:
  targetDevice:
    board: D601-F103-V2
    mcu: STM32F103
  workspace:
    path: /workspace/project
    toolchain: keil-mdk
    keilProject: firmware/demo.uvprojx
    keilTarget: Debug
  debugProbe:
    type: daplink
    adapter: keil
    probeUid: 3FD750C63E342E24
    programBackend: keil
  ioProbe:
    uart:
      id: uart/1
      port: COM9
      baudrate: 115200
  nodeBinding:
    nodeId: node-d601-pc-host
    nodeType: pc-host
```

最低校验要求：

- `kind` 必须为 `Hwpod`。
- `spec.targetDevice`、`spec.workspace`、`spec.debugProbe`、`spec.ioProbe` 必须存在。
- `spec.nodeBinding.nodeId` 必须存在。
- `spec.workspace.path` 必须存在。

Keil MDK 装配规则：当 `spec.workspace.toolchain` 为 `keil-mdk`、`keil`、`mdk` 或 `uv4` 时，`hwpod-compiler-cli` 可以直接从 `hwpod-spec` 生成 `debug.build` / `debug.download` 的 node-side command。`spec.workspace.keilProject` 或 `spec.workspace.projectPath` 指向 `.uvprojx`，相对路径按 `spec.workspace.path` 解析；`spec.workspace.keilTarget` 或 `spec.workspace.targetName` 指向 Keil target。`spec.debugProbe.probeUid` 用于固定 DAP-Link/CMSIS-DAP 选择，`spec.debugProbe.programBackend` 默认按 Keil UV4 工程链路下载。标准下载语义必须由 compiler 生成 Keil `flash` 命令，让 build+program 留在同一个 Keil 异步 job 中；不得依赖预先存在的 artifact、手工 uvoptx 状态或旧 profile 副作用。只有 `spec.debugProbe.autoBindUvoptx` / `autoBindProbe` 显式打开时，compiler 才生成 probe-binding 写回步骤。自动生成的 Keil 计划必须使用已有 `cmd.run` op，并用 `command` + `argv` 传递参数；`probeName`、Windows 路径和 target 名称必须作为独立 argv 元素，不得依赖 `cmd.exe /c`、PowerShell 或 `&&` 拼接来保真带空格参数。Keil 长任务默认异步启动，后续用 `hwpod-cli job status <jobId>` 查询；该入口仍编译为 `cmd.run` 调已有 Keil CLI，不新增 node op。

`spec.workspace.buildCommand`、`spec.debugProbe.downloadCommand` 和 `spec.debugProbe.resetCommand` 仍是调试覆盖出口；标准 case 和 Code Agent runner 不应依赖这些字段长期手写 Keil 主流程。旧 `device-host-cli` / device pod profile 不再作为 compiler 输入权威，相关工程、target、probe 和下载 backend 信息必须迁入 `hwpod-spec`。

## hwpod-node-ops

`hwpod-node-ops` 不表达用户意图，只表达 node 可执行的基础动作。当前新增能力边界收敛为文件读写/patch 类 op 加 `cmd.run`：有 `cmd.run` 就能覆盖 host 上成熟 CLI、编译器、下载器、串口工具和维护命令，再加上受控文件读写即可支撑源码修改 case。后续新增 case 不应因为 build、download、job status、UART、reset 或某个调试工具需要而新增专用 node op；这些业务翻译必须优先落在 `hwpod-compiler-cli` / `hwpod-cli` 组合层。

基础 op 集合：

| op | 用途 |
| --- | --- |
| `node.health` | 查询 node 存活和基础状态 |
| `node.version` | 查询 node runtime 版本 |
| `node.inventory` | 查询 workspace/probe/io 能力 |
| `workspace.ls` | 列目录 |
| `workspace.cat` | 读文件 |
| `workspace.rg` | 递归搜索文件内容，标准别名还有 `grep` / `search` |
| `workspace.apply-patch` | 应用 Codex apply_patch envelope 源码补丁 |
| `cmd.run` | 通用 host 命令透传，用于组合 Keil、serial-monitor、job status、下载、复位和临时维护动作 |

`workspace.rg` 是查找符号、结构体、函数签名和错误文本的标准入口。它在 node 侧直接做受限递归文本搜索，不依赖目标 host 预装 `rg`，并支持 `--context`、`--before-context`、`--after-context`、`--max-matches`、`--max-files`、`--max-bytes-per-file` 和 `--max-line-bytes`。输出会保留结构化 `matches`、`scannedFiles`、`truncated` 和 `limits`，用于在不爆炸输出的前提下追踪上下文。需要精准读整文件时才用 `workspace.cat`；查找 ARM-2D 头文件、函数原型或 Demo 入口时，优先用 `workspace.rg` / `workspace.search`，不要再把 `cat` 管道给 shell `grep`。

若历史实现中仍存在 `debug.*` 或 `io.*` 这类专用 op，它们只能作为兼容存量观察对象，不再作为新 case 或新 harness 业务的扩展方向。标准路径是：compiler 根据 spec 生成 `cmd.run` 的 `command` + `argv`，node 只负责在目标 host 上忠实执行并返回 stdout/stderr/exit code。

`hwpod-node` 是 HWPOD 的唯一受控节点执行器。第一阶段的业务扩展优先落在 `hwpod-compiler-cli` / `hwpod-cli`，通过已有文件读写 op 和 `cmd.run` 组合 Keil、serial-monitor 等成熟工具；不要因为某个 case 需要 build、job status、download、UART 或临时维护动作就新增专用 node op。`cmd.run` 的命令解析、PATH 稳定性和跨平台差异必须在 `hwpod-node` 本体内处理；当 Windows service、后台进程或 D601 host 的环境变量与交互 shell 不一致时，不得用 gateway shell、手工 PowerShell、预先手工创建 worktree 或其他旁路代替 `hwpod-node-ops -> hwpod-node`。D601/Windows 实地调试应使用 UniDesk SSH 透传 `D601:win` 观察进程、PATH、工具安装位置和日志，但修复必须回到 `hwpod-node` 源码、配置或启动入口，并用 `/v1/hwpod-node-ops` 原链路复测。只有 `cmd.run` 自身的执行语义、环境继承或可见性不满足真实 host 执行时，才修改 `hwpod-node`；否则优先改 compiler/CLI。

Windows subject worktree 文本修改优先使用 `workspace.apply-patch`，不要把 `cmd.run` 的 PowerShell/cmd quoting 当成标准编辑路径，也不要把旧 `workspace.write` / `workspace.replace` / `workspace.insert-after` 当成新 case 的推荐入口。文本编辑结果必须返回编辑前后 SHA、文件字节数、换行类型、diff 摘要和 dry-run 状态；`apply-patch` 匹配失败时必须返回 normalized preview、候选行号、CRLF/LF 统计、文件 SHA/bytes 和 hwpod-node implementation version，便于判断是上下文不匹配、CRLF 问题还是远端实现版本问题。`workspace.apply-patch` 应保留原文件换行风格，尤其不能把 CRLF subject 文件静默改写成 LF。

UART read 默认由 compiler 把 `hwpod-cli uart read` 编译为已有 `cmd.run` 内的一段短序列，调用节点本地 `serial-monitor` CLI 的 `monitor start` 和 `fetch --session-only`。两步必须在同一个 `cmd.run` 内顺序执行：`monitor start` 的 JSON 若返回 `success:false`，该 `cmd.run` 必须以非 0 退出并停止，不得继续 fetch 旧会话数据。默认绑定路径是 `C:\Users\liang\.agents\skills\serial-monitor`，也可通过 `spec.tooling.serialMonitorDir`、`spec.ioProbe.serialMonitorDir` 或 CLI 参数覆盖；`spec.ioProbe.uart.port` 和 `spec.ioProbe.uart.baudrate` 是物理串口和波特率权威。串口采集失败时必须把 serial-monitor 的 stdout/stderr、exit code 和 command argv 原样留在 `cmd.run` result 中；不得静默伪造空读数，也不得要求 Agent 改走手写 PowerShell/串口脚本旁路。

标准 plan 形态：

```json
{
  "contractVersion": "hwpod-node-ops-v1",
  "planId": "plan_xxx",
  "hwpodId": "hwpod-local-demo",
  "nodeId": "node-d601-pc-host",
  "intent": "workspace.ls",
  "ops": [
    { "opId": "op_001", "op": "workspace.ls", "args": { "path": "." } }
  ]
}
```

每个 op 的结果第一版保持简单：

```ts
type HwpodNodeOpResult = {
  opId: string;
  op: string;
  ok: boolean;
  status: "completed" | "blocked" | "failed";
  exitCode?: number;
  stdout?: string;
  stderr?: string;
  summary?: string;
  blocker?: { code: string; summary: string } | null;
};
```

## CLI 入口

快速阶段的源码入口使用 Bun 直接运行 TypeScript 文件；runner 或 skill 可以把这些入口暴露为短命令：

```bash
bun tools/hwpod-ctl.ts spec validate --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-compiler-cli.ts compile --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --intent workspace.ls --args '{"path":"."}'
bun tools/hwpod-cli.ts inspect --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --dry-run
bun tools/hwpod-cli.ts workspace read projects/01_baseline/User/main.c --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts workspace rg arm_2d_init projects/01_baseline/Middlewares/Arm-2D --context 3 --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
cat patch.txt | bun tools/hwpod-cli.ts workspace apply-patch --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --reason "edit subject workspace through hwpod-node"
bun tools/hwpod-cli.ts download --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts job status <jobId> --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts uart read --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --port uart1
bun tools/hwpod-node.ts serve --host 127.0.0.1 --port 19678
```

`hwpod-cli` 的正常任务路径是：按 `hwpod-id` 从 runtime service resolve HWPOD document、应用 workspace override、编译 node-ops plan、交给 `hwlab-api`，最后输出 closeout/result。`hwpod-ctl` 的管理路径用于校验 resolved document 和 node 链路；本地 YAML 修改只用于显式 debug/import/export。

## HWPOD CLI 调试入口分层

HWPOD 调试固定保留两种入口，二者必须调用同一套 `hwpod-cli` / `hwpod-ctl` / `hwpod-compiler-cli` 组合层，并最终走 `/v1/hwpod-node-ops` 到目标 `hwpod-node`。不要因为入口不同而复制下载、编译、串口或 job status 逻辑，也不要为 build、download、UART 或 job status 新增 node 专用 op。

### 人工单步直调 hwpod-cli

人工或维护 agent 定位 CaseRun 卡点时，优先在 G14 v0.2 workspace 直接调用 `hwpod-cli` 的单步命令。调用前必须加载 v0.2 CLI API key 和 runtime endpoint，并显式传入 `--hwpod-id` 和本次 subject worktree 的 `--workspace-path`；resolved HWPOD document 是 DAPLink、Keil target、COM 口和波特率的输入权威，workspace path 是本次运行的覆盖参数。

```bash
. /root/.config/hwlab-v02/master-server-admin-api-key.env
export HWLAB_RUNTIME_API_URL=http://74.48.78.17:19667
export HWLAB_RUNTIME_WEB_URL=http://74.48.78.17:19666
export HWLAB_RUNTIME_ENDPOINT_LOCKED=1

bun tools/hwpod-ctl.ts spec validate --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts inspect --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts workspace cat projects/01_baseline/User/main.c --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts workspace rg arm_2d_init projects/01_baseline/Middlewares/Arm-2D --context 3 --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts build --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts download --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts job status <jobId> --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
bun tools/hwpod-cli.ts uart read --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --port uart1 --max-bytes 4096
```

直调入口只用于单步定位和原链路复测：`build` / `download` 返回 Keil async job accepted 只能证明命令已投递，不能等同于编译或下载成功；必须继续用独立短命令 `hwpod-cli job status <jobId>` 轮询终态，不要把轮询包进 `sleep &&`、`timeout`、`watch`、`head`、pipe 或 shell loop。解释结果时结合 `uart read`、Keil result 或目标串口日志。串口被人工工具占用时，应先释放 COM 口或读取已有 serial-monitor 数据解释现象，不得把 COM 口占用误判成 DAPLink、目标板或 API 不可用。

### CaseRun 让 code agent 调 hwpod-cli

CaseRun 验证 code agent 能力时，runner 的职责是布置舞台，而不是代替 agent 完成源码修改或硬件动作。标准流程是：CaseRun 从 case registry 读取 `case.json` 和 HWPOD 引用，创建 subject 隔离 worktree，把 `hwpodId` 与 `hwpodWorkspaceArgs` 写入 agent prompt/context，再把当前 HWPOD CLI/skill 文件随 AgentRun gitbundle workspace 一起提供给 code agent。runner 不再要求 `.hwlab/hwpod-spec.yaml` 进入 AgentRun workspace。

code agent 必须在自己的 AgentRun workspace 内调用同一套入口，例如：

```bash
hwpod-ctl spec validate --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod inspect --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod workspace cat projects/01_baseline/User/main.c --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod workspace rg arm_2d_init projects/01_baseline/Middlewares/Arm-2D --context 3 --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
cat patch.txt | hwpod workspace apply-patch --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --reason "edit subject workspace through hwpod-node"
hwpod build --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod download --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod job status <jobId> --hwpod-id d601-f103-v2 --workspace-path <run-worktree>
hwpod uart read --hwpod-id d601-f103-v2 --workspace-path <run-worktree> --port uart1 --max-bytes 4096
```

对 Code Agent 而言，Keil/HWPOD 长任务同样遵循 cli-spec 短连接组合：`build` 或 `download` 只负责返回 async job id，`job status` 必须作为独立短命令少量轮询；若仍处于 running，应报告 job id、status、diagnostics 和当前判断，不要用长 shell 等待把 agent 子阶段拖成黑盒。

CaseRun prompt 只能描述任务、边界、允许修改的文件、必须尝试的 HWPOD 命令和需要回报的 raw output/job id/串口尾部；不得把具体源码补丁、预期答案或自动评价逻辑写成 prompt。CaseRun result 负责归档 agent session id、trace id、agent message、final response、workspace diff、HWPOD command trace 和 registry run 产物；不做 evidence 自动评价、不做门禁、不把 runner 后置命令伪装成 agent 命令。若某个步骤卡住，先用人工单步直调入口复测同一 spec 和同一 subject worktree，确认是 HWPOD CLI/Keil/serial-monitor/hwpod-node 业务问题后再修复对应组合层或 node 本体。

## CaseRun 无服务阶段

第一阶段 CaseRun 不引入常驻调度服务，由 `hwlab-cli case` 组合 case registry repo、本地 `.state`、`hwpod-cli`、`hwpod-compiler-cli`、`hwlab-api` 和在线 `hwpod-node` 完成单次运行。标准 case registry repo 是 `pikasTech/hwlab-case-registry`，本地默认 checkout 路径是 `/root/hwlab-case-registry`；历史 `pikasTech/hwpod-cases` 只作为迁移前来源。case registry repo 提供 `cases/<caseId>/case.json` 与 HWPOD spec 或 `hwpodId` 引用；每次运行会先在 subject repo 本地 checkout 下创建隔离 Git worktree，再把 `hwpodId` 与该 worktree 路径组合成 `hwpodWorkspaceArgs`。run-local YAML 可作为审计或 runner 后置对照产物保存，但不能作为 Code Agent runner 的注入合同。

CaseRun 的 case registry repo 与 subject repo 必须分离。标准 registry repo 是 `pikasTech/hwlab-case-registry`，G14 标准 checkout 是 `/root/hwlab-case-registry`；历史 `pikasTech/hwpod-cases` 和 `/root/hwpod-cases` 只作为迁移前来源，不再作为新 CaseRun 入口或写入目标。case registry repo 只保存 `case.json`、HWPOD spec 或 spec 引用、`subject` 引用、期望结果和 `runs/<caseId>/<runId>/` 审计产物；它不保存或替代实际固件、工程、测试样例或产品代码库。subject repo 是被开发、被测试、被编译或被下载验证的真实源码仓库，`case.json.subject` 必须明确写入 `repoLocalPath` 和 `commitId`，其中 `repoLocalPath` 是绑定 HWPOD node 上的本地 Git checkout，`commitId` 是完整 40 字符 subject commit id。`case run` 准备阶段只能从 `repoLocalPath` 执行 `git worktree add --detach <worktree> <commitId>`，不得 clone/fetch GitHub，也不得把 branch、tag 或当前 HEAD 作为执行依据或 fallback。若 HWPOD spec 声明 Keil MDK 工程，准备阶段还必须把同名 `.uvoptx` / `.uvopt` sidecar 从 `repoLocalPath` 同步到 isolated worktree，并在 prepare 结果里暴露 copied/missing 诊断；这些 sidecar 承载 CMSIS-DAP/UV4 探头绑定、flash sequence 和 reset/run 配置，不能被 git worktree 的 tracked-file 视角静默丢失。`subdir` 只描述 subject repo 内的 case 关注区域，不能替代 `spec.workspace.path` 的隔离 worktree。`evidence.json` 必须记录 subject repo 本地路径、subject commit、subdir 和 run-local worktree，避免把 floating ref 或外部脏 workspace 当作可审计证据。

标准 `case.json` 的 subject 字段形态如下：

```json
{
  "subject": {
    "repoLocalPath": "F:\\Work\\HWLAB-CASE-F103",
    "commitId": "df7a4e6e551fa90d64bde5537cc000f89d63dd20",
    "subdir": "projects/01_baseline"
  }
}
```

每个 case 必须按任务难度独立配置 agent 阶段等待窗口，避免用单一全局 timeout 误判长任务或拖慢短任务。优先在 `agentTask.timeoutMs` 写入该 case 的 Code Agent 预期窗口；需要统一组织多个阶段 timeout 时，也可以写顶层 `timeouts.agentTimeoutMs`，但 CLI 显式参数 `--agent-timeout-ms` / `--timeout-ms` 仍作为人工单次覆盖。`timeoutMs` 只控制 CaseRun 等待 agent terminal/result 的窗口，不是 evidence 自动评价、门禁或成功判定。未配置时 CLI 兜底为 600000ms；case 可按难度显式收紧或放宽，当前 CLI 上限为 3600000ms。

### CaseRun 当前实现边界

当前 `d601-f103-v2-compile` 是 compile-only smoke，用于验证 case registry repo 与 subject repo 分离、`repoLocalPath` 加 `commitId` 的 subject provenance、隔离 subject worktree、`hwpodId`/workspace binding 和 D601 Keil 编译证据。它不创建 HWLAB Code Agent session，不调用 DS/DeepSeek/provider，不向 Code Agent 下发任务 prompt，不等待 agent trace，也不验证 agent 在源码仓库内完成修改。因此，compile-only CaseRun 是 HWPOD runner 和 Keil 编译底座 smoke，不是 Code Agent 能力评测。

### CaseRun 目标边界：布置舞台与任务 prompt

目标形态中，`case run` 的职责是布置 subject worktree、HWPOD spec、工具入口、上下文包和任务 prompt，再创建或调用 HWLAB Code Agent / AgentRun session，让 Code Agent 在隔离 worktree 内完成源码修改、分析或调试任务。`case run` 可以等待 agent terminal state、读取 workspace diff、执行 build/download/UART smoke、收集 evidence 和判定验收；不得替 Code Agent 生成补丁、直接修改 subject source 或把 deterministic runner 实现当作任务答案。对于“增加一行打印代码”这类 case，源码 diff 必须来自 Code Agent session，runner 只能验收该 diff。边界跟踪见 [pikasTech/HWLAB#976](https://github.com/pikasTech/HWLAB/issues/976)。

agent-task CaseRun 的 evidence 必须至少记录：subject repo 本地路径、subject commit、隔离 worktree、任务 prompt 来源、Code Agent session/trace/provider/model、agent 产生的 workspace diff、验证动作和验证结果。compile-only smoke 的 evidence 不得伪造或补写 agent provenance。

Agent compile-only 阶段必须走 HWLAB Code Agent / AgentRun 的成熟入口：CaseRun 负责生成 prompt/context、创建或调用显式 Code Agent session，并通过 `case run start/status/result/logs` 轮询终态；prompt 必须要求 agent 在自己的 AgentRun workspace 内使用 gitbundle 装配出的标准 `hwpod` / `hwpod-ctl` 工具执行 compile-only 验证。CaseRun 可以保留 runner 后置 compile 作为收尾或对照证据，但 evidence 必须把 agent trace 中的 HWPOD commandExecution 与 runner 后置 `hwpod-cli build` 分开记录，不得把 runner 直接编译伪装成 agent 编译。

CaseRun 是强化学习 Harness 的最小执行单元，但它本身不是完整 epoch。完整 epoch 还需要样本选择、策略生成、奖励/评价、批量调度、跨 run 归因和自动训练闭环；第一阶段只要求一个 `caseId` 能从 case registry repo 进入真实 HWPOD 编译闭环，并把可审计产物稳定落盘。

最小入口：

用法详见 `hwlab-caserun` skill，包含同步运行、异步 start/status/result/logs、分步 prepare/build/collect 和 provider profile 选择等完整用法。

`case run` 在当前版本只负责编排流程和记录原始证据，不做 evidence 自动评价、自动打分或门禁判断。流程是：prepare 先在 subject repo 本地 checkout 下创建 `.worktree/caserun-<runId>` 隔离 worktree，解析 `hwpodId` 并生成 `hwpodWorkspaceArgs`，然后生成 Code Agent prompt/context，创建或调用 HWLAB Code Agent session，把 isolated worktree、`hwpodId`、`hwpodWorkspaceArgs`、任务目标和约束交给 Code Agent；agent 阶段结束或超时后，CaseRun 记录 agent identity、terminal result 里已有的终态字段、trace lookup hint、subject worktree 的 `git status` / `git diff --stat` / `git diff --binary`，再按 case 定义执行 runner 后置 `hwpod-cli build` 和 `cmd.run` Keil 异步 job-status 查询，最后把原始证据和可读归档写入 case registry repo 的 `runs/<caseId>/<runId>/`。固定归档包括 `evidence.json`、`summary.md`、`run.json`、`result.json`、`agent-prompt.md`、`agent-diff.patch`、worker stdout/stderr、`artifact-manifest.json`，以及 `agent-messages.json`、`agent-trace.md`、`agent-transcript.md` 和 `final-response.md`；run-local YAML 若存在，只是审计/对照产物，不是 runner 注入合同。`agent-trace.md` / `agent-transcript.md` 必须包含 trace lookup hint、renderer 标识和 subject diff 区块；如果归档了完整 rendered rows，其语义必须来自共享 Web/CLI trace renderer，不能由 CaseRun 自行发明。`final-response.md` 在 terminal result 存在权威 finalResponse 时保存正文，不存在时显式记录 `finalResponse=null`、terminal/error rows 和缺失原因。下载不作为 compile-only CaseRun 的隐式步骤；后续需要下载时，应作为独立 action 显式加入 case 定义和流程记录。

CaseRun 下发给 HWLAB Code Agent 的请求不得再携带 ad hoc `workspaceFiles` 或 source tree 工具种子；当前工具和 skills 必须由 AgentRun `ResourceBundleRef.kind="gitbundle"` 装配，固定把 repo `tools/` 复制到 workspace `tools/`，把 repo `skills/` 复制到 workspace `.agents/skills`。这不是把 prompt 写成答案，而是保证 Code Agent 看到的 `hwpod` 能力、help、wrapper 和 `cmd.run` 组合语义与当前 `v0.2` 源码一致。若 agent 报告标准 `hwpod` 命令缺失或 help 明显过时，优先修 gitbundle runtime assembly 或 HWPOD CLI/skill 装配，不新增 hwpod-node 专用 op，也不把业务动作旁路到 shell 脚本。

CaseRun 的 trace 处理必须遵循 [spec-v02-code-agent-trace.md](spec-v02-code-agent-trace.md) 的组合优先原则：CaseRun 只负责稳定返回和归档 `traceId`、`sessionId`、`conversationId`、`threadId`、AgentRun 执行线索以及 `traceLookup.commands.*`，完整 trace/result/session 读取继续使用已有 `hwlab-cli client agent trace/result/inspect`。CaseRun 不应在自身内部再实现一套 `/v1/agent/chat/trace/{traceId}` 查询器、row renderer、session 反查或 final response 归因逻辑；如果已有 agent CLI 的 trace 可见性不足，先改进 `client agent trace/result/inspect`，再让 CaseRun 输出新的 ID 或 hint。归档中的 `agent-trace.json` 可以是 `lookupOnly=true` 的 identity manifest，表示“用这些 ID 调既有 CLI 查完整 trace”，不能伪装成完整 trace dump。

长时间 CaseRun 必须优先使用 `case run start/status/result/logs` 短连接形态，而不是用 shell/nohup 包装同步 `case run`。`start` 只负责创建 `.state/hwlab-cli/caserun/<runId>/`、启动后台 worker 并立即返回 `runId`、PID、stdout/stderr 路径和下一条查询命令；`status`、`result`、`logs` 都是短查询。`run.json` 是阶段状态权威，阶段开始时就要刷新 `status`、`stage`、`traceId/sessionId/conversationId/threadId`、AgentRun/trace 轮询信息、stdout/stderr byte count 和下一条轮询命令；长等待期间不得出现无输出、无 trace、无状态文件更新的黑洞窗口。

当前标准 smoke case 是 `d601-f103-v2-compile`。它绑定已发现并预装的 `D601-F103-V2` HWPOD spec，目标是让 CaseRun 通过 Web 等价入口或 AgentRun runner 布置 Code Agent 舞台，再调用 `hwlab-cli case run d601-f103-v2-compile` 跑完整流程，而不是由操作员手工编译后代替运行。当前版本的结果只要求记录：subject provenance、agent prompt/session/trace/conversation/provider、subject worktree diff 文件、HWPOD build invocation、Keil job/status/artifact 字段、`compileOnly=true` 和 `downloadSkipped=true`；不得把这些 evidence 自动归纳为 Code Agent 通过/失败。

产物归属按两条线分开：

- case registry repo 的 `runs/<caseId>/<runId>/` 是 CaseRun 审计产物权威入口；`.state/hwlab-cli/caserun/<runId>/` 只保留短连接控制和轮询所需状态，不作为长期产物入口。registry run 目录必须包含 trace manifest，manifest 只记录文件哈希、agent trace/session、subject provenance、diff 和 Keil job 字段，不引入自动评价或门禁结论。
- `case run`、异步 worker 完成收口和 `case run result` 刷新归档后，默认必须把当前 `runs/<caseId>/<runId>/` 目录自动 `git add`、`git commit` 并 `git push origin HEAD` 到 case registry repo；只允许提交当前 run 目录，不得顺带提交 registry 里其他历史未跟踪 run。`registrySync` 必须写入 result/summary，说明 `pushed`、`unchanged` 或失败阶段。`--no-case-repo-record` 是完全不记录 registry 的诊断出口；`--no-case-repo-git-sync` / `--no-registry-git-sync` 只用于特殊本地调试，不能作为正常 CaseRun 产物收口方式。
- HWLAB repo 的 harness、`hwpod-cli`、`hwpod-ctl`、`hwpod-compiler-cli` 或文档改进可以按风险进入 `v0.2` 分支；单纯文档和轻量 CLI/helper 变更可直接提交，业务代码、运行面或发布链路变更走 PR 工作流。

### CaseRun registry 聚合阅读入口

`hwlab-cli case aggregate <caseId> --run-id <runId> --case-repo /root/hwlab-case-registry` 是已完成 CaseRun 的无服务二次整理入口。它只读取 case registry repo 里已有的 `runs/<caseId>/<runId>/` 产物，不启动新的 CaseRun、不访问硬件、不触发 CI/CD、不追加自动评价或 pass/fail 判定；默认输出 `runs/<caseId>/<runId>/aggregate.md`，并只把这个 markdown 文件 `git add`、`git commit`、`git push` 回 case registry repo。若 registry 里存在其他并行 dirty 产物，`case aggregate` 不得顺带提交它们。

`aggregate.md` 是该 run 的主阅读入口，必须按固定顺序聚合运行环境信息、HWPOD 信息、Code Agent 信息、输入 Prompt、低噪声 Trace、final response 和最后 diff。Trace 正文优先使用共享 Web/CLI renderer rows；普通 message row 直接加粗展示正文，不做折叠，只有工具调用 row 使用 `- <details>/<summary>` 列表项折叠，且 `<summary>` 本身就是折叠按钮，文案写成单行截短的 `已运行 <command>`。工具调用展开体和新生成的 `agent-trace.json` 必须保留完整 command/stdout/stderr/exitCode 正文和结构换行，不能把详情挤成一行，也不能在 full trace 产物里做 preview 截断；只允许 summary 截短。缺少 rows 时才嵌入已有 `agent-trace.md`。聚合文件可以列原始产物索引和 trace/result/inspect 命令作为审计线索，但不能把 `summary.md`、`result.json`、`final-response.md` 或原 trace 文件继续声明为对外主阅读路径。

验收已完成 case04 时，使用现有 registry 产物回放，不重新启动 CaseRun：

```bash
hwlab-cli case aggregate d601-f103-v2-arm2d-integration \
  --case-repo /root/hwlab-case-registry \
  --run-id <existing-case04-run-id>
```

通过证据至少包括 CLI JSON 输出中的 `action=case.aggregate`、`autoEvaluation=false`、`aggregate.rel=runs/<caseId>/<runId>/aggregate.md`、`registrySync.status`，以及打开 `aggregate.md` 后能在单文件内读到上述七类内容。

当前边界：CaseRun 仍是无服务化短连接 CLI 编排，不负责排队、并发、评分、自动合并、长期 run retention 或 epoch 汇总；这些能力属于后续强化学习 Harness 层。CaseRun 也不负责代替 HWLAB Code Agent 完成研发任务，后续 agent-task CaseRun 必须把 prompt/session/trace/diff/evidence 作为一等输出。AgentRun 私有 GitHub repo git transport 必须具备有界失败和可观测性后，才能把单次 CaseRun 扩展为批量 runner 或 epoch 系统。

## 验收标准

快速阶段最小验收：

1. `hwpod-ctl spec validate --hwpod-id <id> --workspace-path <run-worktree>` 能从 runtime service resolve HWPOD document，并验证四要素和 node binding。
2. `hwpod-compiler-cli compile` 能把同一个 `hwpod-id`、workspace override 和高层 intent 编译为稳定 `hwpod-node-ops-v1` plan。
3. `hwpod-cli --dry-run` 输出的 plan 不读取 runner-local `.hwlab/hwpod-spec.yaml`，也不读取其他本地旧 profile authority。
4. `hwlab-api` 的 node-ops 入口能接收 plan，返回 JSON result；无可用 node 时必须返回结构化 blocker，而不是静默伪造 DEV-LIVE。
5. 真实 CLI 验收必须证明 `hwpod-cli -> hwpod-compiler-cli -> hwlab-api /v1/hwpod-node-ops -> hwpod-node` 全链路走通。
6. CaseRun 流程必须能用 `hwlab-cli case run <caseId>` 从 case registry repo 读取 case 定义，按 `subject.repoLocalPath` 和 `subject.commitId` 创建隔离 subject worktree，生成 Code Agent prompt/context，记录 agent session/trace/conversation/provider，采集 subject worktree diff，执行 compile-only smoke，并产出 isolated run state 和 case registry repo 全量产物归档；当前版本只记录流程证据和 trace manifest，不设置通过条件、不自动评价 evidence，并明确记录 downloadSkipped。
7. 长任务验收必须覆盖 `hwlab-cli case run start <caseId>` 立即返回，以及 `status/result/logs <runId>` 在 worker 运行中能短查询到阶段、耗时、stdout/stderr byte count、trace/session/conversation/thread 信息和下一条轮询命令；不得把同步命令长时间无输出视为有效 CaseRun 操作体验。
8. `d601-f103-v2-compile` 的真实流程只覆盖当前编排链路和 compile-only smoke；操作员直接运行 `hwpod-cli build`、直接调用 Keil 或只检查 node 侧 job，不等同于 CaseRun 流程跑完。
9. agent-task CaseRun 的真实流程必须证明 `case run` 已创建或调用 Code Agent / AgentRun session，任务 prompt 已进入 agent 上下文，CaseRun 已采集隔离 subject worktree diff，并已继续执行编译、下载或 I/O smoke 等后续动作；当前版本只记录这些事实，不自动判断 agent 是否完成任务。
10. 已完成 run 的 registry 聚合验收必须通过 `hwlab-cli case aggregate <caseId> --run-id <runId>` 输出单个 `aggregate.md`，并证明该文件包含运行环境、HWPOD、Code Agent、Prompt、低噪声 Trace、final response 和最后 diff；Trace 中 message 加粗直接展示，工具调用用 `- <details>` 缩进和单行截短的 `已运行 <command>` summary 折叠，展开后保留完整详情换行。新归档的 `agent-trace.json` 也必须保存 full trace row body，不得把 tool detail 压缩为 preview。该命令不得启动新 CaseRun，也不得提交当前聚合 markdown 以外的并行 registry dirty 文件。
11. Windows subject worktree 文本编辑必须能在 CRLF 文件中通过 `workspace.apply-patch` 完成源码修改，返回 before/after SHA 与 diff 摘要，并保留原文件 CRLF；`workspace.apply-patch` 在 context 不匹配时必须返回可诊断 payload，而不是只给 `context not found`。
12. Keil `debug.download` 自动装配必须输出结构化 `cmd.run` argv 步骤；带空格的 `probeName` 在 plan 中必须是单独 argv 元素。`io.uart.read` 必须通过节点本地 `serial-monitor` 读取正在监控的 COM/baud；未监控或工具失败时必须返回包含 `ioProbe`/COM 口/baud/monitor status/启动建议的结构化 blocker details。
