444 lines
58 KiB
Markdown
444 lines
58 KiB
Markdown
# PJ2026-010403 API契约
|
||
|
||
## 修改历史
|
||
|
||
| 版本 | 对应 commit id | 更新日期 | 变更说明 |
|
||
| --- | --- | --- | --- |
|
||
|
||
当前正文仍在规格治理草稿中;未定稿前不新增版本号,不为单次编辑追加 `待提交` 版本。
|
||
|
||
## 正文
|
||
|
||
## PJ2026-010403 API契约需求规格
|
||
|
||
## 1. 文档控制
|
||
|
||
| 字段 | 内容 |
|
||
| --- | --- |
|
||
| 编号 | PJ2026-010403 |
|
||
| 短名 | API契约 |
|
||
| 层级 | L2 课题 |
|
||
| 状态 | 已生效 |
|
||
| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-22-p1-workbench-redis-derived-cache; draft-2026-06-27-p0-workbench-read-api-contract; PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority; PJ2026-01050105 Web鉴权 draft-2026-06-18-p0-auth |
|
||
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
|
||
| 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) |
|
||
| 关联规格 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
|
||
| 规格治理索引 | [规格治理](spec-governance.md) |
|
||
|
||
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版:正文只保留 API 契约的稳定使命、范围、术语、系统边界、内部分工和原子需求。
|
||
|
||
## 2. 目的和范围
|
||
|
||
### 2.1 目的
|
||
|
||
API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RESTful HTTP API 入口语义,使同一用户请求在 Web、CLI 和 HTTP 调用下使用一致的 method、path、query/body、schema、鉴权主体、错误语义和结果标识。
|
||
|
||
本课题的目标状态是:客户端入口可以通过同源 API 证明业务路径是否可用;后端业务事实改变时,API 契约负责稳定暴露字段和错误,而不在客户端侧发明第二套事实模型。
|
||
|
||
### 2.2 范围内
|
||
|
||
- Cloud Web 同源相对 REST/JSON path、route policy 和绝对 URL 禁止边界。
|
||
- Web session、API key、AuthPrincipal、actor 摘要和权限错误在客户端入口中的表达。
|
||
- Agent session、chat、steer、cancel、result、trace 和 inspect 的用户可见 API 形态。
|
||
- CaseRun case list、run admission、run status、events、aggregate、artifact manifest、cancel 和 HWPOD/AgentRun 引用的用户可见 API 形态。
|
||
- 项目管理 navigation/projects/MDTODO source/file/task/workbench-link REST 资源、HWPOD-bound Source 配置、file content、task mutation、ProjectTask DTO、Workbench launch intent DTO 和独立项目管理服务代理边界。
|
||
- Workbench workspace、Admin Access、provider profile、HWPOD node-ops、gateway 和性能摘要等入口的字段稳定性。
|
||
- JSON 成功/失败响应、HTTP 状态、错误分类、脱敏、默认摘要和完整展开边界。
|
||
- Workbench pure-read API 的缓存诊断字段,包括 `cacheStatus`、`cacheAgeMs`、projection revision/seq、dbQueryAvoided 和 Redis unavailable/stale 的低基数表达。
|
||
|
||
### 2.3 范围外
|
||
|
||
- 用户、组织、API key、额度、role、OpenFGA relation 和账本真相归 [用户管理](PJ2026-0105-user-management.md)。
|
||
- AgentRun run、command、runner job、session continuation 和 provider runtime 归 [Agent编排](PJ2026-0102-agent-orchestration.md)。
|
||
- HWPOD 资源身份、硬件操作、node 路由和原始硬件事实归 [硬件池](PJ2026-0101-hardware-pool.md)。
|
||
- CaseRun、评价、aggregate、回放和训练反馈归 [HarnessRL](PJ2026-0103-harness-rl.md)。
|
||
- ProjectSource、MDTODO adapter、Markdown 任务投影、ProjectWorkbenchLink 和外部 PM adapter 归 [项目管理](PJ2026-010404-project-management.md)。
|
||
- 运行端点、FRP/Caddy、Secret、rollout 和 Prometheus 监控归 [平台运维](PJ2026-0106-platform-ops.md)。
|
||
- Redis workload、镜像、资源、NetworkPolicy、TTL 数值、metrics scrape 和运行面发布归 [平台运维](PJ2026-0106-platform-ops.md) 与 [Workbench性能](PJ2026-01060505-workbench-performance.md);API契约只定义客户端可见字段和诊断边界。
|
||
|
||
## 3. 术语表
|
||
|
||
| 术语 | 定义 |
|
||
| --- | --- |
|
||
| 同源 API | Cloud Web origin 下的相对 REST/JSON HTTP API path,供浏览器和 HWLAB CLI 使用。 |
|
||
| route policy | 哪些 path 可以通过 Cloud Web 代理、哪些只能作为显式 Cloud API 诊断或内部服务调用的边界规则。 |
|
||
| AuthPrincipal | 后端根据 Web session 或 API key 恢复出的用户主体摘要。 |
|
||
| CanonicalPrincipal | `/auth/session` 和受保护业务 route 共享的最小身份结果,包含 `authMethod`、`identityAuthority`、`sessionKind`、actor 摘要和后端 capability 摘要;它是业务 route 的唯一身份输入。 |
|
||
| 业务标识 | sessionId、turnId、traceId、runId、commandId、caseId 等用户可继续查询的稳定标识;projectId、workspaceId 和 conversationId 只能作为筛选、metadata 或兼容映射字段,不作为前端鉴权 authority。 |
|
||
| CaseRun resource | Cloud Web origin 下表达 CaseRun case、run、stage、event、aggregate 和 artifact manifest 的 RESTful 资源集合。 |
|
||
| Project Management resource | Cloud Web origin 下表达项目、source、MDTODO 文件、任务、Workbench link 和项目能力的 RESTful 资源集合。 |
|
||
| HWPOD-bound Source DTO | 项目管理 API 中表达 `sourceKind=hwpod-workspace`、`hwpodId`、`nodeId`、workspace 相对根、capability、probe status 和脱敏 blocker 的 Source 配置对象。 |
|
||
| ProjectTask | 项目管理 API 返回的任务 DTO,包含 `taskRef`、`projectId`、`sourceId`、title、status、父子关系、linkCount 和脱敏 metadata。 |
|
||
| ProjectTask mutation | 对 MDTODO 任务 title/body/status/add/delete/reindex 的显式写入资源;必须带 expected revision 或 fingerprint,并由项目管理服务写入 Markdown source-of-truth。 |
|
||
| `taskRef` | 项目管理 opaque 任务引用;API 可以转发和保存,Workbench、Cloud Web 和 CLI 不得解析其内部结构。 |
|
||
| WorkbenchLaunchIntent | `POST /v1/workbench/launches` 的请求 DTO,用于把项目任务上下文传给 Workbench session admission。 |
|
||
| ProjectWorkbenchLink | 项目管理 API 返回的任务到 Workbench session/trace 的链接摘要,只表达 ID 指针和脱敏状态。 |
|
||
| Run admission | 接收 CaseRun 提交并返回 `202 Accepted`、runId、statusUrl 和下一步查询入口的短返回 mutation。 |
|
||
| selected origin mode | 客户端入口从 YAML 解析出的 origin 模式,至少区分 `public` 和 `internal`;API 只看到同源请求,不反推或硬编码入口地址。 |
|
||
| 错误语义 | HTTP status、错误码、blocker、failureKind、route 和下一步提示组成的可定位失败表达。 |
|
||
| W3C trace context | `traceparent` / `tracestate` / `baggage` 等跨进程传播上下文;API 响应只允许把 `traceparent` 和脱敏后的 OTel trace id 暴露给客户端,不向用户展示 `tracestate`、`baggage` 或上游私有上下文。 |
|
||
| OTel trace_id | OpenTelemetry/W3C trace context 中的 16-byte 非全零 trace id,以 32 位十六进制字符串表达;它用于从用户截图或复制信息跳转到 trace backend,不替代业务 `traceId`、`sessionId`、`runId` 或权限判断。 |
|
||
| HwlabErrorEnvelope | API 用户可见失败响应的统一 JSON envelope,承载错误 code、用户文案、分类、层级、retryable 和脱敏诊断字段。 |
|
||
| ErrorDiagnostic | 错误诊断字段集合,至少包含 OTel trace id、request id、route、serviceId、observedAt 和 `valuesRedacted=true`;它只用于排障和复制,不参与 Workbench lifecycle 或 final response 判断。 |
|
||
| Session detail | `GET /v1/workbench/sessions/{sessionId}` 这类按稳定 sessionId 或后端认可 opaque session handle 查询当前会话 metadata、消息指针和状态的 RESTful detail resource。 |
|
||
| Conversation detail | 迁移期兼容资源;可返回 conversation metadata、sessionId、threadId 和 message seed,但不得继续作为 Web deep link 或前端 active session authority。 |
|
||
| TurnSnapshot | 按 turnId 或 traceId 查询一次用户提交/steer/retry/cancel 生命周期、终态、message 指针和执行引用的 RESTful snapshot。 |
|
||
| TraceEventPage | 按 traceId 和 cursor/seq 分页查询 trace events 的 RESTful page;只表达 trace 明细,不决定主 timeline 的 final response。 |
|
||
| Message/Part | Web 和 CLI 共同渲染会话 timeline 的持久消息事实;message 表达角色、父子关系和终态摘要,part 表达文本、工具、文件、错误、trace 摘要等可组合内容。 |
|
||
| Timing metadata | Workbench DTO 中用于显示消息最近事件和轮次耗时的投影时间字段,至少包括 `startedAt`、`lastEventAt`、`finishedAt` 和 sealed `durationMs`;相对 age 只能由浏览器显示层用本地 now 临时计算。 |
|
||
| EventStream | Cloud Web origin 下的 SSE 实时入口,用于推送 server.connected、session、turn、message、part、trace 和 workspace lifecycle 事件。 |
|
||
| WorkbenchEventMapper | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的 direct publish 组件,把 `agentrun.event.v1` 转换为 `hwlab.event.v1`,不要求内联数据库事务。 |
|
||
| WorkbenchReadModel | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的唯一读模型,从 durable Workbench facts 组装 session detail、message page、turn snapshot、trace event page 和 session rail summary。 |
|
||
| Workbench event stream | `hwlab.event.v1` append-only Kafka event stream;API 只暴露其 revision、cursor 和 replay envelope,不得建立第二 API 事实源。 |
|
||
| Serve Session Authority | 会话级 typed event 权威;API mutation 提交执行命令,GET/SSE/compat wrapper 不得建立数据库 outbox authority。 |
|
||
| eventSeq/aggregateSeq | Workbench event stream 的全局 cursor 与 aggregate 内 cursor,用于 SSE replay、projection revision、新鲜度和乱序检测;它们与 AgentRun `sourceSeq` 分离。 |
|
||
| Derived read cache | WorkbenchReadModel 内部可选的 Redis 派生读缓存;它只缓存 durable projection 派生快照,不改变 API 资源、权限、lifecycle 或 final response 语义。 |
|
||
| CacheDiagnostic | Workbench pure-read 响应或 OTel span 中用于解释缓存行为的诊断字段集合,至少包含 `cacheStatus`、`cacheAgeMs`、cacheKeyClass、projectionSeq 或等价字段;它不参与业务状态判断。 |
|
||
| cacheStatus | 缓存行为枚举,至少包含 `hit`、`miss`、`stale`、`unavailable`;该字段只能用于性能诊断和 `/performance` 展示,不得用于推断 session/turn/trace lifecycle。 |
|
||
| projection commit | projection writer/finalizer 对 message、part、turn、trace 和 session summary 的一次幂等持久化提交;终态 commit 必须保持这些事实语义一致。 |
|
||
| projectedSeq | HWLAB durable trace event 的单调分页游标;与 AgentRun `sourceSeq` / `sourceEventId` 分离,用于 Workbench trace page、SSE replay 和 fake-server fixture。 |
|
||
| 读侧推理 | API route、read model、SSE consumer、compat wrapper、CLI renderer、Web reducer/selectors、fake-server 或测试断言根据 trace tail、message text、tool event、result cache、session summary、list row、workspace snapshot、localStorage 或 elapsed timeout 推断 lifecycle、terminal、running 或 final response 的行为;API契约禁止该模式。 |
|
||
|
||
## 4. 系统边界和接口
|
||
|
||
本规格把 API契约作为客户端方向下的接口语义层看待;本章只描述输入、输出和责任边界。
|
||
|
||
| 边界项 | 内容 |
|
||
| --- | --- |
|
||
| 外部使用者 | Cloud Web、HWLAB CLI、自动化脚本、平台管理员和需要同源 API 的浏览器客户端。 |
|
||
| 外部输入 | HTTP method、相对 path、JSON body、query、Web session cookie、Authorization header、`traceparent`、sessionId、turnId、traceId 和业务参数;projectId、workspaceId、conversationId 只允许作为显式筛选或兼容 metadata 输入。 |
|
||
| 受控资源 | API path、schema、route policy、AuthPrincipal 摘要、错误码、响应摘要和兼容性契约。 |
|
||
| 外部输出 | JSON 响应、HTTP status、`traceparent`、`x-hwlab-otel-trace-id`、`x-request-id`、route、actor、业务标识、错误分类、脱敏状态、trace/result 指针、cache diagnostic 和下一步查询提示。 |
|
||
| 用户接口 | Cloud Web 同源 API、HWLAB CLI 同源 REST request/client 命令、HTTP API。 |
|
||
| 系统边界 | API契约负责接口形态和错误表达;不拥有用户、Agent、硬件、CaseRun、账本或发布事实。 |
|
||
|
||
## 5. 内部分工与规格索引
|
||
|
||
| 编号 | 模块或课题 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| PJ2026-01040301 | 同源路由 | 本规格 6.1 | Cloud Web 相对 REST/JSON path、route policy 和绝对 URL 禁止边界 | 平台入口、Web工作台 | HWLAB CLI、Cloud Web |
|
||
| PJ2026-01040302 | 鉴权主体 | 本规格 6.2 | Web session、API key、actor 摘要和权限错误表达 | 用户管理 | Web、CLI、业务 API |
|
||
| PJ2026-01040303 | Agent接口 | 本规格 6.3 | conversation、session、chat、steer、cancel、result、trace 和 inspect API 形态 | Agent编排、用户管理 | Web工作台、HWLAB CLI |
|
||
| PJ2026-01040304 | 资源接口 | 本规格 6.4 | workspace、access、provider、HWPOD node-ops、gateway 和性能摘要入口 | 全部业务 L1 | Web、CLI、admin |
|
||
| PJ2026-01040305 | 错误输出 | 本规格 6.5 | JSON 成功/失败响应、错误码、route/status、脱敏和渐进披露 | 全部业务 L1 | 用户、脚本、排障 |
|
||
| PJ2026-01040306 | 缓存诊断 | 本规格 6.6 | Workbench pure-read cache diagnostic 字段、脱敏边界和禁止状态仲裁 | Workbench实时权威、Workbench性能 | Web、CLI、Performance 页 |
|
||
| PJ2026-01040307 | CaseRun接口 | 本规格 6.7 | CaseRun case/run/status/events/aggregate/cancel REST 资源、短返回和错误语义 | HarnessRL、硬件池、Agent编排 | Web CaseRun、CLI、web-probe |
|
||
| PJ2026-01040308 | 项目管理接口 | 本规格 6.8 | 项目管理 REST 资源、MDTODO DTO、Workbench launch intent、link 查询和独立微服务代理边界 | 项目管理、Web工作台、用户管理 | `/projects`、`/projects/mdtodo`、CLI、web-probe |
|
||
|
||
目标后端模块应至少拆分为 route/handler、schema/contract、read model、persistence/projection、AgentRun adapter、trace event pager、SSE/event publisher 和 compat wrapper。route 文件只负责 HTTP 入口、鉴权桥接和错误映射;schema/contract 只负责类型和字段;read model 只组装查询模型;adapter 只转换外部执行事实;projection 只写 durable facts;compat wrapper 只提供旧 path 到新资源的兼容映射,不拥有第二套业务事实。
|
||
|
||
### 5.1 Workbench实时权威 API 边界
|
||
|
||
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 集中定义 `agentrun.event.v1 -> hwlab.event.v1 -> live/replay SSE` 的目标架构。API 契约只保留接口边界:SSE 从 Kafka cursor 回放并切到同一 live tail;`GET /v1/workbench/*` 只读非阻塞派生模型;compat wrapper 只能调用正式 mutation 或只读接口。
|
||
|
||
Workbench mutation API 必须在 AgentRun durable admission 成功后短返回 `202 Accepted`,并包含可继续关联的 `sessionId`、`turnId`、`traceId`、`commandId` 或 no-op reason。`POST /v1/agent/chat`、steer、cancel 和 retry 不得等待 PostgreSQL projection、outbox、migration、runner 启动、result polling 或 trace hydration;派生读模型失败只能形成 warning/diagnostic,不能把已接纳命令改写为 admission failure。
|
||
|
||
Workbench SSE/event API 必须按 `hwlab.event.v1` Kafka cursor replay。`GET /v1/workbench/events?afterSeq=N` 或等价入口返回的每条 envelope 至少应携带 Kafka cursor、`sessionId`、`turnId`、`traceId`、entity family/id/version、`projectionRevision` 和脱敏 payload 摘要。回放追上水位后必须在同一连接切到 live tail;缺口进入 transport diagnostic 和 Kafka retention replay,禁止 REST 补洞或数据库 outbox replay。
|
||
|
||
若 AgentRun 事实已经 terminal 但 Workbench projection 尚未追平,GET 响应应暴露 `projectionStatus`、`lastProjectedSeq`、`sourceRunId`、`sourceCommandId`、`blocker` 或等价诊断字段;不得在 GET 中同步调用 AgentRun、Code Agent manager、legacy conversation manager、billing finalizer、workspace repair、trace polling 或 result polling 来推进事实。读模型、SSE publisher、compat wrapper 和 CLI render 都不能各自解释 terminal、running、final response 或 trace pagination;它们只能重放 durable projection。
|
||
|
||
API 契约严禁读侧推理。`GET /v1/workbench/*`、`/v1/agent/*` compat wrapper、SSE event envelope 和 CLI render 只能返回唯一 Workbench durable projection 中已经存在的 lifecycle/final/status 字段;不得从 `result?.status ?? trace?.status`、最后一条 trace event `completed`、message text 是否为空、part/tool row 状态、session list summary、workspace selected state、轮询耗时或 elapsed timeout 合成 terminal、running、finalResponse 或 `caught-up`。投影缺失或矛盾时返回结构化 unknown/projecting/degraded/blocker,而不是在读侧选择一个优先级最高的事实源。
|
||
|
||
Derived read cache 只能作为 WorkbenchReadModel 内部性能优化。`GET /v1/workbench/*` 可以返回 `cacheStatus`、`cacheAgeMs`、cacheKeyClass、projectionSeq、dbQueryAvoided 或等价 CacheDiagnostic 字段,用于解释 hit/miss/stale/unavailable 和读路径耗时;这些字段不得影响 HTTP resource identity、AuthPrincipal、owner visibility、lifecycle、terminal、finalResponse、projectionStatus、404/410 判断或 compat wrapper 映射。Redis unavailable 时,API 只能返回 `cacheStatus=unavailable` 加受控 DB read 或明确 degraded,不能让 liveness 失败,也不能切换到 Cloud API/Web 前端 Redis 直连。
|
||
|
||
### 5.2 Workbench pure-read DTO 字段矩阵
|
||
|
||
`GET /v1/workbench/*` 的响应 DTO 只表达已经提交的 durable Workbench projection 和独立诊断。API 可以为渐进披露裁剪长字段,但必须保留 authority 边界和可继续查询的稳定标识。
|
||
|
||
| DTO | 必需身份字段 | lifecycle/final 字段 | diagnostic 字段 | 禁止解释 |
|
||
| --- | --- | --- | --- | --- |
|
||
| SessionRailItem | `sessionId`, `currentTurnId` 可空 | `status`, `running`, `summary`, `updatedAt` | `projectionStatus`, `blocker` 可空 | 用 list row 推断当前 message final 或 trace terminal。 |
|
||
| SessionDetail | `sessionId`, `threadId`/`conversationId` metadata 可空 | `status`, `running`, `currentTurnId`, `messagePageCursor` | `projectionStatus`, `lastProjectedSeq`, `sourceRunId`, `sourceCommandId`, `blocker` | 在 detail GET 内调用 AgentRun、workspace repair 或 result sync 推进事实。 |
|
||
| MessagePage | `sessionId`, `messageId`, `partId`, `turnId` | `role`, `status`, `sealedAt`, `parts[].finalResponse` | part/message diagnostic 可空 | 根据空 text、trace tail 或 result cache 合成 assistant final。 |
|
||
| TurnSnapshot | `turnId`, `traceId`, `sessionId`, `sourceRunId`, `sourceCommandId` | `status`, `terminal`, `failureKind`, `sealedAt`, `messageIds` | `projectionStatus`, `lastProjectedSeq`, `blocker` | 根据最后一条 trace event、轮询耗时或 transport error 推断 terminal。 |
|
||
| TraceEventPage | `traceId`, `range`, `events[].projectedSeq` | trace event `type/status` 和 durable terminal event | `hasMore`, `nextCursor`, `sourceSeq/sourceEventId` 审计字段 | 用 `hasMore=false` 推断 turn terminal;混用 `sourceSeq` 和 `projectedSeq` 作为 cursor。 |
|
||
| EventStreamEnvelope | `eventSeq`/`outboxSeq`, `aggregateId`, `aggregateSeq`, `sessionId`, `turnId`, `traceId` | 已投影 commit 的 notification,不直接承载第二套 lifecycle | `projectionRevision`, `commitType`, `replay`, `gap`, `valuesRedacted=true` | 按 SSE 到达顺序重排 timeline;用 event payload 直接覆盖 read model。 |
|
||
| ProjectionDiagnostic | `sessionId`, `turnId`, `traceId`, `sourceRunId`, `sourceCommandId` | 无主 timeline 写权 | `projectionStatus`, `health`, `lag`, `lastProjectedSeq`, `sourceLatestSeq`, `blocker`, `updatedAt` | 把 diagnostic 文案覆盖 sealed final response。 |
|
||
| TransportDiagnostic | `sessionId`, `turnId`, `traceId` 可空 | 无主 timeline 写权 | SSE、poll、hydration、result sync 或 network health | 把 transport failure 改写成 message/turn terminal 状态。 |
|
||
|
||
Workbench message/turn DTO 可以输出 timing metadata,但字段权威必须保持单一:`startedAt`、`lastEventAt`、`finishedAt` 和 sealed `durationMs` 来自 Workbench durable projection;running 消息的“最近/耗时”由浏览器以这些时间戳和本地 now 计算;terminal 消息使用 sealed `durationMs` 或等价 sealed `finishedAt - startedAt`,不得继续增长。`lastEventAgeMs` 若在迁移期保留,只能作为服务端观测时刻的快照或诊断字段,不能作为 Cloud Web 用户可见相对时间的显示权威,也不能参与 lifecycle、terminal、projectionStatus、session sorting 或 final response 选择。
|
||
|
||
Workbench pure-read DTO 可以携带 CacheDiagnostic,但字段必须与业务事实分仓表达。`cacheStatus`、`cacheAgeMs`、`cacheKeyClass`、`projectionSeq`、`dbQueryAvoided`、`dbQueryDuration` 和 `payloadBytes` 只能放在 `diagnostic`、`performance`、`meta` 或等价非 authority 字段下;默认响应不得输出完整 cache key、actor id、session id 以外的派生 key、trace id 组合 key、prompt、assistant 正文、tool 参数、stdout/stderr、Secret、token、cookie、Authorization header 或 DB DSN。客户端可以显示或上报这些诊断用于性能分析,但不得把 `hit` 视为新鲜、把 `stale` 视为 terminal、把 `unavailable` 视为业务失败,或根据 cache miss 触发 read-through repair。
|
||
|
||
API 禁止路径清单如下:GET read-through repair、session JSON lifecycle 推理、result cache lifecycle 推理、trace tail lifecycle 推理、workspace/conversation authority、billing finalizer side effect、Code Agent manager shortcut、frontend status priority 和 compat wrapper second authority。需要推进 projection 时必须由 writer/finalizer、后台 scheduler、显式 mutation 或受控 replay/reprojection 入口执行;GET、SSE、CLI render 和 fake-server 只能观察结果。
|
||
|
||
### 5.3 Workbench cache diagnostic 数据流
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Client[Web / CLI] --> Route[GET /v1/workbench/*]
|
||
Route --> Auth[AuthPrincipal + owner visibility]
|
||
Auth --> Read[WorkbenchReadModel]
|
||
Read --> Cache[(Derived Redis cache)]
|
||
Cache -->|hit with matching authority input| Dto[Pure-read DTO]
|
||
Cache -->|miss / stale / unavailable| Facts[(Durable Workbench facts)]
|
||
Facts --> Read
|
||
Read --> Dto
|
||
Dto --> Diag[CacheDiagnostic meta]
|
||
Diag --> Client
|
||
```
|
||
|
||
缓存诊断数据流要求 route 先完成鉴权和 owner visibility,再由 WorkbenchReadModel 使用 durable facts authority input 访问 Redis 派生缓存。cache hit 只能返回等价 pure-read DTO;cache miss、stale 或 unavailable 必须回到 durable facts read 或明确 degraded,不得触发 AgentRun、result polling、workspace repair、projection finalizer 或前端 Redis 直连。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as Web/CLI
|
||
participant A as Cloud API route
|
||
participant R as WorkbenchReadModel
|
||
participant K as Redis derived cache
|
||
participant F as Durable facts
|
||
C->>A: GET /v1/workbench/sessions
|
||
A->>R: principal + query + route
|
||
R->>K: get cache key with authority input
|
||
alt hit and revision matches
|
||
K-->>R: derived DTO + cacheAgeMs
|
||
else miss/stale/unavailable
|
||
R->>F: read durable projection
|
||
F-->>R: authoritative DTO or degraded/blocker
|
||
R->>K: set derived snapshot when allowed
|
||
end
|
||
R-->>A: DTO + CacheDiagnostic
|
||
A-->>C: JSON response, lifecycle from durable projection only
|
||
```
|
||
|
||
## 6. 原子需求
|
||
|
||
### 6.1 CLIENT-API-REQ-001 同源路由
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-001 | 同源路由 | PJ2026-01040301 同源路由 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-010402 HWLAB CLI](PJ2026-010402-hwlab-cli.md)、[平台运维](PJ2026-0106-platform-ops.md) |
|
||
|
||
API契约应定义 Cloud Web origin 下的相对 REST/JSON path 和 route policy,使浏览器与 HWLAB CLI 能通过同一同源入口访问业务 API。
|
||
|
||
同源路由必须拒绝把绝对 URL、内部服务地址或旧运行面端口作为正式用户入口。平台运维提供公开入口和代理支撑;API契约只规定客户端可依赖的 path 和错误形态。
|
||
|
||
API契约必须区分同源 API path 与浏览器 history route:`/auth*`、`/v1*`、`/health*` 等 API path 返回 JSON 语义,`/workbench`、`/login` 和其他 Cloud Web 页面路由由 Web工作台处理。API/edge 直达入口对页面路由返回 JSON 404 是正确边界,不应被改造成 SPA fallback;反过来,Web正式公开入口必须通过 route policy 把 API path 分流到 API 服务。
|
||
|
||
RESTful API 必须保持无状态请求语义:在相同 method、path、query、body、auth 主体和相同后端业务事实下,应返回同一语义结果;服务端不得为了补齐某个列表或状态而隐藏读取浏览器 workspace selected、localStorage、Web snapshot、上一次页面状态或其他客户端临时状态。列表窗口需要包含某个当前资源时,必须通过显式 query/path/body 传入稳定业务 id,例如 session list 通过显式 include session id 请求把当前 session 纳入同一列表响应;服务端只能从当前 Web session/API key 恢复 AuthPrincipal,校验该 id 对当前 actor 是否可见并返回后端事实,不得接受客户端拼接出的 project、workspace、status、final response、markdown、running 动效或 stub 作为事实来源。
|
||
|
||
当前会话消息恢复必须使用 session 主路径:`GET /v1/workbench/sessions/{sessionId}` 返回 session metadata 和消息指针,`GET /v1/workbench/sessions/{sessionId}/messages` 返回 message/part page,turn 和 trace 分别由 `TurnSnapshot` 与 `TraceEventPage` 补洞。`GET /v1/workbench/workspace` 可以返回 selected ids、workspace revision 和 composer 配置,但不得成为消息本体 authority;`GET /v1/workbench/sessions` 可以返回 rail 摘要和显式 include 的列表项,但不得替代当前 session detail/message page。前端恢复、深链、刷新和 session 切换必须以稳定 sessionId 或后端认可 opaque session handle 调用同一 detail/message resource,不得在 detail resource 失败时切到 workspace snapshot、conversation detail、列表摘要、JSON-RPC、内部 manager、浏览器缓存或空 stub 继续构造当前消息面板。
|
||
|
||
### 6.2 CLIENT-API-REQ-002 鉴权主体
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-002 | 鉴权主体 | PJ2026-01040302 鉴权主体 | [用户管理](PJ2026-0105-user-management.md)、[PJ2026-010402 HWLAB CLI](PJ2026-010402-hwlab-cli.md) |
|
||
|
||
API契约应以 AuthPrincipal 摘要表达 Web session 和 API key 恢复出的当前用户,使 Web、CLI 和 HTTP API 可以一致处理未登录、无权限、账号禁用、额度不足和工具能力缺失。
|
||
|
||
鉴权主体的真相由用户管理负责。API 响应只输出 actor、authMethod、requiredAuthMethod、role/status、scope 摘要和错误分类,不输出 session token、完整 API key、password hash、Secret value 或可复用凭据。
|
||
|
||
`/auth/session` 是 Cloud Web 的最小身份验证端点。浏览器请求只依赖同源 `hwlab_session` cookie transport;前端不得向该端点传入 API key、user-billing token、cookie prefix、localStorage token 或第二套 authority。该端点成功时必须返回 canonical principal,至少包含:
|
||
|
||
| 字段 | 语义 | 脱敏边界 |
|
||
| --- | --- | --- |
|
||
| `authenticated` | 当前请求是否已通过认证 | 布尔值 |
|
||
| `authMethod` | 认证 transport 来源,例如 `web-session`、`user-billing-session`、`user-billing-api-key`、`local-bootstrap` | 枚举,不输出 token |
|
||
| `identityAuthority` | 身份事实归属,例如 `hwlab-local`、`user-billing`、`bootstrap-recovery` | 枚举,不输出底层凭据 |
|
||
| `sessionKind` | 调用形态,例如 `browser`、`api-key`、`recovery` | 枚举 |
|
||
| `actor` | 当前用户摘要,至少包含稳定 id、role、status;可包含 username/displayName | 不输出 password hash、session secret、完整邮箱验证 payload |
|
||
| `capabilities` | 后端授权摘要,例如 `web`、`workbench`、`codeAgent`、`billing`、`admin` | 只输出 `available`、`forbidden`、`unlinked`、`unavailable` 或等价短枚举 |
|
||
| `valuesRedacted` | 响应是否遵守脱敏边界 | 必须为 true |
|
||
|
||
未登录请求必须返回 401 和结构化 unauthenticated 结果;禁用、撤销或 recovery 能力不足必须返回 403 或业务 blocker,并保留 `authMethod`、`identityAuthority`、`sessionKind` 的可诊断摘要。响应不得输出 cookie、session token、API key secret、完整 user-billing token、provider Secret、DB DSN 或 raw dependency payload。
|
||
|
||
业务 route 只能消费认证层产生的 canonical principal 和权限配额的 capability 结果。Usage、Billing、API keys、Workbench、Code Agent 和 Admin route 不得自行调用 token/cookie 抽取函数来决定用户身份;如果需要访问 user-billing、API key 或账单后台,应由后端以 principal 为输入桥接业务服务,并把 `available/forbidden/unlinked/unavailable` 或结构化 blocker 返回给客户端。
|
||
|
||
### 6.3 CLIENT-API-REQ-003 Agent 用户接口
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-003 | Agent接口 | PJ2026-01040303 Agent接口 | [Agent编排](PJ2026-0102-agent-orchestration.md)、[用户管理](PJ2026-0105-user-management.md)、[PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md) |
|
||
|
||
API契约应定义显式 Agent session、turn、chat、steer、cancel、result、trace 和 inspect 的用户可见 RESTful HTTP 形态,使 Web 和 HWLAB CLI 能围绕同一 sessionId、turnId、traceId、runId 和 commandId 操作。conversationId、threadId 可以作为后端返回的 metadata 或兼容映射字段存在,但不得替代 sessionId 成为 Web deep link 或 active authority。
|
||
|
||
Agent 接口不得通过 session latest、浏览器历史、旧 cache 或内部 manager 生成第二套 final response。Agent编排提供执行事实,用户管理校验 owner 和权限,客户端只稳定暴露用户入口。
|
||
|
||
Trace 查询必须采用无状态 RESTful 资源形态:`GET /v1/agent/traces/{traceId}` 是客户端读取 Code Agent trace events、runnerTrace、terminalEvidence、finalResponse 和 traceSummary 的权威入口。请求只依赖 method、path、query、auth 主体和后端业务事实;Web 不得使用动作式 `/v1/agent/chat/trace/{traceId}` 作为恢复会话、切换 session 或 completed 消息加载 trace 的前端路径,也不得把浏览器 workspace snapshot、localStorage 或消息 stub 拼成 trace 响应。
|
||
|
||
Trace resource 必须支持按事件位置继续读取,例如 `sinceSeq` / `cursor` 与 `limit` 这类 query 参数。服务端返回超长 trace 时应按完整事件边界截断,并在同一个资源响应中给出 `range`、`hasMore`、`nextSinceSeq` 或等价阶段性位置,使客户端可以继续请求下一段;响应不得返回半条事件,不得要求 JSON-RPC、回放按钮、内部 manager path 或第二套 trace endpoint 才能补齐完整可读事件。分页请求必须保持无状态和幂等:同一 `traceId`、同一位置参数、同一权限主体下重复请求不得污染 trace 事实。
|
||
|
||
`POST /v1/agent/chat`、`GET /v1/agent/turns/{traceId}` 和 result 入口可以返回 `traceUrl` 指针,但该指针必须指向 RESTful trace resource。trace resource 可以为了短返回默认裁剪事件,但完整事件补齐、终态 final response、AgentRun run/command identity、错误和脱敏边界仍由同一 trace resource 表达;客户端不得要求用户手动“回放 Trace”才能获得完成态 trace。
|
||
|
||
目标 Workbench RESTful API 资源设计如下。旧 `/v1/agent/*` 路径可以作为兼容 wrapper 暂存,但 Web 主路径应逐步收敛到这些资源语义。
|
||
|
||
| 资源 | Method / path | 请求字段 | 响应主体 | 状态码 | 权威边界 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| WorkspaceSelection | `GET /v1/workbench/workspace` | `projectId`, `workspaceId` 可选 | selected ids、workspace revision、composer 配置、public origin 摘要 | 200/401/403 | 只读 selection/config,不返回或修补 message 事实 |
|
||
| WorkspaceSelection | `PATCH /v1/workbench/workspace` | 显式 selected project/workspace/conversation ids | 更新后的 selection/config | 200/400/401/403 | 只有显式 mutation 可改变 selection |
|
||
| Session list | `GET /v1/workbench/sessions` | `cursor`, `limit`, `includeSessionId`,可选后端认可筛选字段 | session/conversation rail 摘要 page | 200/401/403 | 当前用户可见 session 列表和排序,不替代 detail |
|
||
| Session detail | `GET /v1/workbench/sessions/{sessionId}` | path sessionId | session metadata、message page 指针和当前 turn/trace 摘要 | 200/401/403/404 | session metadata,不拥有 trace events |
|
||
| Message page | `GET /v1/workbench/sessions/{sessionId}/messages` | `cursor`, `limit`, `before/after` | message + parts page、next cursor | 200/401/403/404 | 会话 timeline 的 message/part 事实 |
|
||
| Conversation detail | `GET /v1/agent/conversations/{conversationId}` | path conversationId | conversation metadata、message page seed、sessionId、threadId、lastTraceId、turn summary | 200/401/403/404 | 迁移期兼容 detail,不替代 session 主路径 |
|
||
| Turn admission | `POST /v1/workbench/sessions/{sessionId}/turns` | prompt/parts、delivery、client message ids、可选 metadata | `202 Accepted` + turnId、traceId、userMessageId、assistantMessageId、status URLs | 202/400/401/403/409/422 | 只表示输入已接收,不表示执行完成 |
|
||
| Turn snapshot | `GET /v1/workbench/turns/{turnId}` | path turnId | status、terminal、message ids、traceId、AgentRun refs、failureKind | 200/401/403/404 | turn 状态补洞,不承载 trace events |
|
||
| Trace event page | `GET /v1/workbench/traces/{traceId}/events` | `afterSeq/cursor`, `limit` | ordered events、range、hasMore、next cursor | 200/401/403/404/410 | trace 明细分页,不决定主 timeline final response |
|
||
| EventStream | `GET /v1/workbench/events` | optional sessionId/turnId/traceId filters | SSE events + heartbeat | 200/401/403 | 实时加速和通知,不替代 REST snapshot |
|
||
| Cancel turn | `POST /v1/workbench/turns/{turnId}/cancel` | reason 可选 | updated TurnSnapshot | 200/202/401/403/404/409 | 精确取消目标 turn |
|
||
| Steer turn | `POST /v1/workbench/turns/{turnId}/steer` | text/parts、delivery | accepted steer TurnSnapshot 或 continuation id | 202/400/401/403/404/409 | 绑定明确 running turn |
|
||
| ProviderProfile | `GET /v1/workbench/provider-profiles` | project/workspace 可选 | profile summary list | 200/401/403 | 配置摘要,不输出 Secret |
|
||
| Diagnostic resource | `GET /v1/workbench/diagnostics/{resource}` | resource id/query | redacted health/status summary | 200/401/403/404 | 诊断可见性,不改变业务事实 |
|
||
|
||
所有 GET path 必须无业务副作用。需要 repair、finalize、sync 或 migration 时,应由后台 finalizer、显式 mutation 或持久化投影入口执行,不能隐藏在 workspace、conversation、turn 或 trace GET 中。所有分页响应必须包含稳定 cursor 或 seq 边界;trace event page 的分页 cursor 使用 HWLAB `projectedSeq`,并保留 AgentRun `sourceSeq/sourceEventId` 作为来源审计字段,二者不得重叠或互相替代。所有错误响应必须包含 route、status、code/blocker、redacted actor、target resource 和下一步建议。
|
||
|
||
`GET /v1/workbench/sessions/{sessionId}/messages` 返回的 MessagePage 必须是会话 timeline 顺序,而不是数据库写入批次顺序。排序键应优先体现 turn timeline/aggregate seq/事件时间;同一 turn 内用户 message 先于 assistant/agent terminal message;同一 session 多轮刷新后不得出现由 read model 排序造成的 role cluster。Message DTO 应保留 `projectedSeq/sourceSeq/sourceEventId` 供审计,但客户端不得把这些来源字段当作唯一排序修复点。
|
||
|
||
`GET /v1/workbench/traces/{traceId}/events` 的可见性必须以 trace 所属 turn/message/session durable facts 和当前 actor visibility 判断。历史 trace 不再是 session 当前 `lastTraceId` 时仍应可读;缺页或投影滞后应返回 projection blocker/degraded,而不是 `workbench_trace_not_found` 的 actor 不可见误导。
|
||
|
||
`GET /v1/workbench/traces/{traceId}/events` 的 continuation 空窗口属于正常分页状态或投影追平窗口,不得返回 404。若 actor 可见且 metadata/checkpoint 表明 trace 仍有未追平区间,API 应返回 `200`、`events=[]`、空 `range.fromProjectedSeq/toProjectedSeq`、原 `nextProjectedSeq`、`status=projecting` 或等价 diagnostic,并暴露 `projectionStatus`、`projectionHealth`、`lastProjectedSeq`、`traceLastSeq`、`fullTraceLoaded=false`、`diagnostic.code=workbench_trace_events_missing`。`404` 只用于真实不可见、未归档、删除或 actor 权限不匹配的 trace,不用于 no-new-events、lag 或 catch-up。
|
||
|
||
Cancel mutation 在转发 AgentRun cancel 前必须核验本地 sealed terminal 或上游 run/command state。若 command 已 terminal,API 应返回 already-terminal/no-op 或触发 terminal projection,不得把 completed/failed/blocked 等真实 terminal 改写为 canceled。Workbench read paths 仍保持纯读,不在 GET 中执行该核验或修复。
|
||
|
||
Workbench read-model dependency timeout 必须返回结构化 degraded/readiness/blocker 响应;PostgreSQL pool connect/query timeout 不得作为未捕获异常杀死 cloud-api 进程,也不得让 liveness 因单次 Workbench read query 变成 EOF。
|
||
|
||
新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority; PJ2026-010403 API契约 draft-2026-06-20-p0-workbench-pure-read-api; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0`,并简述文件职责。实现文件不得只写 issue 编号、`latest` 或 `current` 作为规格引用。
|
||
|
||
### 6.4 CLIENT-API-REQ-004 资源与管理接口
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-004 | 资源接口 | PJ2026-01040304 资源接口 | [硬件池](PJ2026-0101-hardware-pool.md)、[用户管理](PJ2026-0105-user-management.md)、[Agent编排](PJ2026-0102-agent-orchestration.md)、[平台运维](PJ2026-0106-platform-ops.md) |
|
||
|
||
API契约应定义 workbench workspace、Admin Access、provider profile、HWPOD node-ops、gateway 诊断和性能摘要等资源与管理入口,使 Web 和 HWLAB CLI 可以一致读取状态、提交操作和展示错误。
|
||
|
||
资源与管理接口只定义调用形态和字段稳定性。HWPOD node-ops 的硬件语义归硬件池,provider profile runtime 归 Agent编排,权限和账号归用户管理,运行健康和公开入口归平台运维。
|
||
|
||
Gateway 相关 API 只允许作为云端同源入口暴露:用户、Agent 或 smoke 调用 Cloud API / API契约中的 gateway/HWPOD path,由 HWPOD 服务再路由到主动出站的 AI 网关。API契约不得要求客户端直接访问用户 PC gateway,也不得把 gateway 本地端口、内网地址或临时 poll URL 写入正式客户端输出。
|
||
|
||
### 6.5 CLIENT-API-REQ-005 错误与输出合同
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-005 | 错误输出 | PJ2026-01040305 错误输出 | [PJ2026-010402 HWLAB CLI](PJ2026-010402-hwlab-cli.md)、[PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[HarnessRL](PJ2026-0103-harness-rl.md) |
|
||
|
||
API契约应保证成功和失败都以可定位 JSON 形式表达,至少包含调用 route、HTTP status、错误码或 blocker、必要业务标识、脱敏 actor 或权限摘要,以及可继续查询的 result/trace/status 入口。
|
||
|
||
默认响应不得输出爆炸或泄漏敏感值;需要完整 trace、原始响应或长日志时,必须通过显式展开参数、下载入口或已有业务产物获取。错误输出只负责说明失败,不替代缺失能力实现。
|
||
|
||
Cloud API 请求入口必须统一 extract 或 create W3C `traceparent`,并把 OTel trace id、span id、request id、route 和 serviceId 绑定到同一次 request context。所有 200、4xx 和 5xx 响应都必须带 `traceparent`、`x-hwlab-otel-trace-id` 和 `x-request-id`;业务 handler、dependency client、dev-entrypoint proxy、AgentRun adapter、user-billing、HWPOD 或其他下游调用只能传播该 context,不能在同一请求内随机生成第二个用户可见 trace id。
|
||
|
||
用户可见 API 失败响应应统一使用 `HwlabErrorEnvelope` 或等价结构:
|
||
|
||
```ts
|
||
interface HwlabErrorEnvelope {
|
||
ok: false;
|
||
status: number | "failed";
|
||
error: {
|
||
code: string;
|
||
message: string;
|
||
userMessage?: string;
|
||
category?: string;
|
||
layer?: string;
|
||
retryable?: boolean;
|
||
diagnostic: {
|
||
traceId: string | null;
|
||
spanId?: string | null;
|
||
requestId?: string | null;
|
||
route?: string | null;
|
||
serviceId?: string | null;
|
||
observedAt: string;
|
||
valuesRedacted: true;
|
||
};
|
||
};
|
||
valuesRedacted: true;
|
||
}
|
||
```
|
||
|
||
`error.message` 和 `error.userMessage` 只承载用户可理解文案;`error.diagnostic.traceId` 承载可复制的 OTel trace id。响应不得向用户外显 `tracestate`、`baggage`、cookie、API key、完整 Authorization header、DB DSN、provider token、prompt、assistant 正文、tool 参数、stdout/stderr 长段、raw upstream payload 或可复用凭据。`traceparent` 可作为标准 header 返回,但默认页面只展示 `trace_id` 字段。
|
||
|
||
错误 envelope 的结构化日志必须记录同一 `trace_id`、`request_id`、`error.code`、route、status 和 layer,使日志、span 和用户错误诊断能关联。`trace_id` 不得作为 Prometheus label;如需 metrics 关联,只能通过低基数 route/status/code label、exemplar 或受控 debug payload 承载。
|
||
|
||
Workbench 投影 blocker、proxy timeout、鉴权失败、provider profile、web-performance、全局 route exception 和 dev-entrypoint proxy 错误都应映射到同一 envelope。历史 `{ error: string }` 字段可在迁移期作为 `userMessage` 展示兼容,但不得成为唯一错误事实;新增用户可见错误路径禁止只返回裸字符串、`reason` 或未脱敏 raw exception。
|
||
|
||
### 6.6 CLIENT-API-REQ-006 Workbench cache diagnostic 字段
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-006 | 缓存诊断 | PJ2026-01040306 缓存诊断 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |
|
||
|
||
Workbench pure-read API 可以在成功或 degraded 响应中输出 CacheDiagnostic,用于说明 Redis 派生读缓存是否命中、是否 stale、是否 unavailable、快照年龄和是否避免 durable DB 查询。该诊断至少应能表达 `cacheStatus=hit|miss|stale|unavailable`、`cacheAgeMs`、cacheKeyClass、projectionSeq 或等价 revision、dbQueryAvoided、dbQueryDuration 和 payloadBytes;字段位置必须与 lifecycle/final/status 分仓。
|
||
|
||
CacheDiagnostic 不得成为业务状态仲裁字段。Web、CLI、compat wrapper、fake-server 和 web-probe 不得根据 `cacheStatus`、`cacheAgeMs`、Redis key presence 或 dbQueryAvoided 推断 session running/completed、turn terminal、trace caught-up、final response、deleted/archived/not-found 或权限可见性。缓存 unavailable 不应触发 `/health/live` 失败;route 可以返回受控 DB read 结果或明确 degraded/blocker,但不能静默切换到 Cloud API/Web 前端 Redis 直连或旧 fallback path。
|
||
|
||
CacheDiagnostic 必须脱敏并保持低基数。响应、日志、OTel span 和 `/performance` 默认展示不得包含完整 cache key、actor id 聚合维度、trace id 组合 key、prompt、assistant 正文、tool 参数、stdout/stderr、Secret、token、cookie、Authorization header、DB DSN 或 raw upstream payload。需要排查单次请求时,只允许通过 OTel trace id、request id、route、cacheKeyClass、projectionSeq 和 valuesRedacted 摘要关联。
|
||
|
||
### 6.7 CLIENT-API-REQ-007 CaseRun 用户接口
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-007 | CaseRun接口 | PJ2026-01040307 CaseRun接口 | [HarnessRL](PJ2026-0103-harness-rl.md)、[硬件池](PJ2026-0101-hardware-pool.md)、[Agent编排](PJ2026-0102-agent-orchestration.md)、[PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md) |
|
||
|
||
API契约应定义 YAML-selected Cloud Web origin 下的 CaseRun RESTful 资源,使 Web、HWLAB CLI 和 web-probe 能通过同一用户身份、同一相对 path 和同一错误 envelope 提交、查询、取消和阅读 CaseRun。origin 是 public 还是 internal 由 node/lane YAML 和客户端端点解析决定,API 契约只要求同源 path 与错误语义一致。
|
||
|
||
目标 CaseRun API 资源设计如下。具体字段可随实现演进,但资源身份、短返回、业务事实归属和禁止后门路径必须保持稳定。
|
||
|
||
| 资源 | Method / path | 请求字段 | 响应主体 | 状态码 | 权威边界 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Case list | `GET /v1/caserun/cases` | 可选 `hwpodId`、`target`、`capability` 筛选 | caseId、描述、目标硬件、stage 模板、所需 HWPOD capability | 200/401/403 | 只列出 HarnessRL 可运行 case,不证明资源当前可用 |
|
||
| HWPOD readiness summary | `GET /v1/caserun/hwpods` 或复用正式 HWPOD spec/readiness 资源 | 可选 caseId | hwpodId、nodeId、capabilities、availability、blocker 摘要 | 200/401/403 | 硬件事实来自硬件池,CaseRun API 只交接摘要 |
|
||
| Run admission | `POST /v1/caserun/runs` | caseId、hwpodId、providerProfile、subjectRef、可选 metadata | `202 Accepted`、runId、statusUrl、eventsUrl、aggregateUrl、traceUrl 可空 | 202/400/401/403/409/422 | 只表示提交被接收,不表示 Agent 或硬件动作完成 |
|
||
| Run list | `GET /v1/caserun/runs` | 可选 status、limit、cursor | 按 createdAt 倒序的 runId、caseId、workflow identity、status、stage、terminal、时间与证据摘要,以及 nextCursor | 200/400/401/403 | 共享 HarnessRL registry 的纯读发现入口;不扫描 CLI 本地文件,不替代详情、事件或 aggregate |
|
||
| Run status | `GET /v1/caserun/runs/{runId}` | path runId | stage、terminal、caseId、hwpodId、nodeId、traceId、AgentRun refs、HWPOD operation summaries、latest blocker | 200/401/403/404 | HarnessRL read model,不直接同步推进 AgentRun 或 HWPOD |
|
||
| Run events | `GET /v1/caserun/runs/{runId}/events` | cursor/afterSeq、limit | stage/event page、next cursor、valuesRedacted | 200/401/403/404 | 事件阅读,不拥有第二套 run 状态 |
|
||
| Run aggregate | `GET /v1/caserun/runs/{runId}/aggregate` | 可选 detail level | aggregate、artifact manifest hash、evidence refs、replay refs、diagnostic | 200/401/403/404/409 | 低噪声结果入口,评价语义归 HarnessRL |
|
||
| Run artifact manifest | `GET /v1/caserun/runs/{runId}/artifacts` | 可选 artifact type | manifest、artifact refs、hash、size、redaction 摘要 | 200/401/403/404 | 只返回索引和允许下载的受控摘要 |
|
||
| Run cancel | `POST /v1/caserun/runs/{runId}/cancel` | reason 可选 | updated Run status 或 accepted cancel refs | 200/202/401/403/404/409 | 精确取消目标 run,不根据最新 run 或页面状态推断 |
|
||
|
||
CaseRun API 的 GET path 必须纯读。投影滞后、AgentRun 未终态、HWPOD node 离线、operation result 缺失、aggregate 未生成或 artifact store 不可达时,GET 应返回 projecting、degraded、blocked 或结构化 failure;不得在 GET 中同步触发 AgentRun dispatch、HWPOD 写操作、workspace repair、result polling finalizer 或旧 CLI 回放。
|
||
|
||
CaseRun API 必须把事实来源分仓输出。AgentRun refs 至少应能指向 runId/commandId/traceId 或等价执行标识;HWPOD refs 至少应能指向 hwpodId、nodeId、leaseId 或 operation result id;HarnessRL refs 至少应能指向 CaseRun runId、stage revision、artifact manifest hash 和 aggregate revision。API 不得把 stdout 尾部、客户端轮询耗时、trace tail、Web DOM、web-probe 报告或人工 issue 评论作为 run terminal 或 pass/fail 事实。
|
||
|
||
web-probe 使用 CaseRun API 时必须保持 YAML-selected origin 下的同源用户路径。它可以通过页面控件或同源正式 mutation 提交 run,并通过同一 status/events/aggregate 资源观察终态;当 YAML 选择 internal origin 时可以使用内部 IP,但仍不得调用未声明的内部 service URL、Kubernetes、Postgres、D601 SSH、本地 gateway 端口、旧 v0.2 runner 或测试 fixture 来补齐 CaseRun 成功证据。
|
||
|
||
### 6.8 CLIENT-API-REQ-008 项目管理用户接口
|
||
|
||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||
| --- | --- | --- | --- |
|
||
| CLIENT-API-REQ-008 | 项目管理接口 | PJ2026-01040308 项目管理接口 | [PJ2026-010404 项目管理](PJ2026-010404-project-management.md)、[PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[用户管理](PJ2026-0105-user-management.md) |
|
||
|
||
API契约应定义 YAML-selected Cloud Web origin 下的项目管理 RESTful 资源,使 Cloud Web、HWLAB CLI 和 web-probe 能用同一用户身份、同一相对 path、同一错误 envelope 和同一脱敏边界访问项目、source、MDTODO 文件、任务、Workbench link 和 Workbench launch intent。
|
||
|
||
目标项目管理 API 资源设计如下。Cloud API 可以作为同源 route/auth bridge 转发到独立 `hwlab-project-management` 微服务,但不得拥有项目管理持久化、Markdown 解析、外部 PM sync、Workbench link 表或 adapter 状态。
|
||
|
||
Cloud API 的 Project Management proxy 必须按同源鉴权和脱敏 envelope 转发下表所有项目管理资源所需的 `GET`、`HEAD`、`POST`、`PATCH` 和 `DELETE` 方法;只允许 `POST /v1/project-management/workbench-links` 这类单点写入的代理白名单是不合规的。代理层不得把 MDTODO source create/update/probe/reindex、file content 写入、task mutation/create/delete 拦截成 404/405,也不得要求 Cloud Web、web-probe 或 CLI 改用私有 service URL 绕过同源入口。
|
||
|
||
| 资源 | Method / path | 请求字段 | 响应主体 | 状态码 | 权威边界 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Navigation | `GET /v1/project-management/navigation` | 可选 `projectId` | 导航可见性、capability、默认 project/source 摘要、blocker | 200/401/403 | 只表达项目入口能力,不返回 raw Markdown |
|
||
| Project list | `GET /v1/project-management/projects` | cursor、limit、可选筛选 | `projectId`、title、source 摘要、visibility、updatedAt | 200/401/403 | 当前 actor 可见项目列表 |
|
||
| MDTODO sources | `GET /v1/project-management/mdtodo/sources` | 可选 projectId | `sourceId`、displayName、sourceKind、root 摘要、read/write capability、parse/index status | 200/401/403 | 不暴露 host path、Secret 或完整 Git remote |
|
||
| MDTODO source create | `POST /v1/project-management/mdtodo/sources` | `sourceKind=hwpod-workspace`、`hwpodId`、`nodeId`、`mdtodoRootRef`、capability | Source DTO、source revision、probe status 可空 | 201/400/401/403/409/422 | 只创建受控 Source 配置,不直接暴露 HWPOD 文件系统 |
|
||
| MDTODO source update | `PATCH /v1/project-management/mdtodo/sources/{sourceId}` | displayName、root/capability patch、expected revision | updated Source DTO | 200/400/401/403/404/409/422 | 更新 ProjectSource registry,不改写任务文件 |
|
||
| MDTODO source delete | `DELETE /v1/project-management/mdtodo/sources/{sourceId}` | expected source revision、confirm impact | deleted sourceId、affected file/task/link counts、audit id | 200/400/401/403/404/409/422 | 禁用或删除 Source 配置,不删除 HWPOD workspace 文件 |
|
||
| MDTODO source probe | `POST /v1/project-management/mdtodo/sources/{sourceId}/probe` | 可选 probe options | HWPOD workspace op 摘要、capability、blocker、timing | 200/202/400/401/403/404/409/422 | 只探测连接和权限,不写任务事实 |
|
||
| MDTODO source reindex | `POST /v1/project-management/mdtodo/sources/{sourceId}/reindex` | expected source revision 可选 | projection status、indexed files/tasks、diagnostics | 200/202/400/401/403/404/409/422 | 从 Markdown 重建 projection,不把 DB 反写为权威 |
|
||
| MDTODO files | `GET /v1/project-management/mdtodo/files` | `sourceId`、cursor、limit | fileRef、displayName、taskCount、status、fingerprint hash、parseError 摘要 | 200/401/403/404 | 文件摘要,不返回完整 Markdown |
|
||
| MDTODO file content | `GET /v1/project-management/mdtodo/files/{fileRef}/content` | `sourceId`、可选 redaction mode | 脱敏 Markdown preview 或 rawContent capability、revision、sha256、parser diagnostics | 200/401/403/404/409/422 | 默认不返回完整 raw Markdown;完整内容必须显式 capability |
|
||
| MDTODO tasks | `GET /v1/project-management/mdtodo/tasks` | `sourceId`、可选 fileRef、parentTaskRef、status/filter、cursor/offset、limit | bounded `ProjectTask[]`、taskRef、父子关系、linkCount、projection revision、page/limit/total/hasMore | 200/401/403/404/409/422 | 任务投影来自项目管理 read model;不得默认返回 source 全量任务 |
|
||
| MDTODO task mutation | `PATCH /v1/project-management/mdtodo/tasks/{taskRef}` | title/body/raw block/status/metadata patch、expected revision | updated ProjectTask、document revision、audit id | 200/400/401/403/404/409/422 | 写入必须经 MDTODO adapter 文件锁和原子写入 |
|
||
| MDTODO task create | `POST /v1/project-management/mdtodo/tasks` | sourceId、fileRef、mode=root/subtask/continue、parent taskRef 可选、title/body、expected revision | created ProjectTask、document revision、audit id | 201/400/401/403/404/409/422 | 生成 Rxx id 并写入 Markdown source-of-truth |
|
||
| MDTODO task delete | `DELETE /v1/project-management/mdtodo/tasks/{taskRef}` | expected revision、confirm impact | deleted taskRef、affected refs、document revision、audit id | 200/400/401/403/404/409/422 | 删除 Markdown task block,必须有影响范围摘要 |
|
||
| Workbench launch | `POST /v1/workbench/launches` | `WorkbenchLaunchIntent`,含 `sourceKind=project-management`、`projectId`、`taskRef`、prompt template | `202 Accepted` 或 200、sessionId、workbenchUrl、linkId、traceId 可空 | 200/202/400/401/403/404/409/422 | Workbench 公共 mutation,不属于 MDTODO 私有 helper |
|
||
| Workbench links | `GET /v1/project-management/workbench-links` | `taskRef`、可选 projectId/sourceId、cursor | linkId、sessionId、traceId、createdBy 摘要、createdAt、role、status | 200/401/403/404 | 只返回 ID 指针和脱敏摘要 |
|
||
|
||
`ProjectSource` DTO 对 HWPOD-bound source 至少应包含 `sourceId`、`projectId`、`sourceKind="hwpod-workspace"`、displayName、`hwpodId`、`nodeId`、`mdtodoRootRef`、read/write capability、probe status、source revision、index status、blocker 可空和 `valuesRedacted=true`。`mdtodoRootRef` 只能是 workspace 相对根,例如 `docs/MDTODO/`;响应不得返回 host absolute path、Secret、session token、完整 file system listing 或未脱敏 node payload。
|
||
|
||
`ProjectTask` DTO 至少应包含 `taskRef`、`projectId`、`sourceId`、`fileRef`、`kind`、`rxxId`、title、status、parentTaskRef、depth、linkCount、document revision、updatedAt 和 `valuesRedacted=true`。Rxx 树的 parentTaskRef 来自 `rxxId` 前缀;fileRef、lineNumber、source fingerprint、Markdown preview 和 parse diagnostic 只能作为脱敏 metadata 输出;默认响应不得包含 host path、raw Markdown、Secret、token、DB DSN、provider payload、完整 prompt 或可复用凭据。
|
||
|
||
`GET /v1/project-management/mdtodo/tasks` 必须是有界读取。未指定 `limit` 时服务端应使用受控默认窗口,指定 `limit` 时必须套用服务端最大值;响应应返回 `total`、`hasMore`、`limit` 和 cursor/offset 摘要。页面首屏应优先读取 source/files 摘要和 selected file 或 selected subtree 的任务窗口;对 `71-FREQ` 这类包含数百个任务的大 source,不得通过一次 source 级全量任务响应支撑默认渲染或 web-probe 验收。
|
||
|
||
MDTODO mutation 请求必须携带 expected document revision、fingerprint 或等价并发条件。服务端发现 revision 不匹配时返回 409,并输出 current revision、conflict code 和下一步建议;不得用读侧修复、last write wins 或前端重试覆盖远端 Markdown 修改。
|
||
|
||
`WorkbenchLaunchIntent` 至少应包含 `sourceKind="project-management"`、`projectId`、`taskRef`、title 摘要、promptTemplateId、optional initial prompt metadata 和 `valuesRedacted=true`。Workbench 可以保存这些字段为 session metadata,但不得反解 taskRef、读取 Markdown、调用 Project Management adapter 或把项目管理 DB 当作 Workbench authority。
|
||
|
||
项目管理 GET path 必须纯读。投影滞后、source 不可用、Markdown parse error、adapter unavailable、link 投影未收敛或 Workbench launch 尚未写回 link 时,GET 应返回 projecting、degraded、blocked 或结构化 failure;不得在 GET 中同步修复文件、触发 Workbench session 创建、调用 AgentRun dispatch、写 DB link、读取运行面 Secret 或访问未声明内部服务。
|
||
|
||
项目管理 API 的错误必须使用 `HwlabErrorEnvelope` 或等价结构,并携带 route、status、code/blocker、resource id 摘要、OTel trace id、request id、serviceId 和 `valuesRedacted=true`。`mdtodo-raw-markdown-leak`、`mdtodo-hostpath-leak`、`mdtodo-taskref-missing`、`mdtodo-source-probe-failed`、`mdtodo-path-out-of-scope`、`mdtodo-document-revision-conflict`、`mdtodo-rxx-parse-error`、`mdtodo-hwpod-node-unavailable`、`workbench-link-projection-missing` 等应作为可分析 code/blocker,而不是只返回裸字符串。
|
||
|
||
web-probe observe/analyze 使用项目管理 API 时必须保持同源用户路径。它可以通过页面控件或同源正式 mutation 触发 Workbench launch,并通过自然请求、Resource Timing、DOM 摘要和 link API 观察结果;不得调用私有 service URL、Kubernetes、Postgres、D601 SSH、localStorage 后门或测试 fixture 来补齐通过证据。
|
||
|
||
## 7. 过程控制
|
||
|
||
本规格不单独索引一般过程 issue;跨 L1 的内测、灰度和阶段活动索引统一保留在 [PJ2026-01 HWLAB 总规格](PJ2026-01-HWLAB.md) 的 `7. 过程控制`。Workbench Redis 派生读缓存架构执行 issue 为 [#1870](https://github.com/pikasTech/HWLAB/issues/1870),P0 SPEC-first 子 issue 为 [#1871](https://github.com/pikasTech/HWLAB/issues/1871),后续实现必须引用 `draft-2026-06-22-p1-workbench-redis-derived-cache`。
|