docs: add Workbench projection SPEC

This commit is contained in:
Codex
2026-06-18 14:50:35 +00:00
parent 9854dbedb0
commit 362926118a
5 changed files with 334 additions and 100 deletions
@@ -140,4 +140,4 @@ Agent编排应原样消费 AgentRun 的 run、command、runner job、event、ter
HWLAB 不应在客户端、adapter 或 prompt 中推断或补造 AgentRun 没有发出的事实。AgentRun 已正确输出时,HWLAB 负责消费和业务映射;AgentRun 合同缺失或行为错误时,应回到 AgentRun 实现与对应 OA 规格修复。
PJ2026-0104010803 唯一投影切片要求 Agent编排只把 AgentRun run、command、event、terminal status、failureKind 和 result envelope 交给 HWLAB接入的 projection writer/finalizer。Agent编排不得让 Web、CLI、Workbench GET、trace polling 或 legacy conversation path 分别读取 AgentRun 并各自推断 session running、assistant final response、turn terminal 或 trace terminal;同一 AgentRun 事实只能形成一份 HWLAB Workbench durable projection。
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 要求 Agent编排只把 AgentRun run、command、event、terminal status、failureKind 和 result envelope 交给 HWLAB接入的 projection writer/finalizer。Agent编排不得让 Web、CLI、Workbench GET、trace polling 或 legacy conversation path 分别读取 AgentRun 并各自推断 session running、assistant final response、turn terminal 或 trace terminal;同一 AgentRun 事实只能形成一份 HWLAB Workbench durable projection。
@@ -56,7 +56,7 @@ HWLAB接入负责把 HWLAB Cloud API、Workbench、CLI、HWPOD 运行上下文
| 手动调度 API | AgentRun 为已存在 run/command 显式创建 runner Job 的短返回 API。 |
| HWLAB canary | HWLAB v0.2 通过 AgentRun 执行真实 Code Agent turn 的最小接入闭环。 |
| result envelope | AgentRun command result 的结构化输出,包含 status、terminalStatus、reply、failureKind、events 和 artifact 摘要。 |
| Workbench projection writer | HWLAB接入中唯一把 AgentRun result envelope 和 events 写成 Workbench session、message、part、turn 和 trace facts 的组件。 |
| Workbench projection writer | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的唯一写入组件,在 HWLAB接入中把 AgentRun result envelope 和 events 写成 Workbench session、message、part、turn 和 trace facts。 |
| HWPOD runtime context | HWLAB dispatcher 为单次 runner job 提供的 owner-scoped 硬件运行上下文。 |
| transientEnv | 单次 runner job 的短期 env 上下文,由 AgentRun 转为短期 Secret 投影并脱敏输出。 |
| 自然语言单一路由 | `/v1/agent/chat` 中自然语言请求统一进入 AgentRun Code Agent turn,不由 Cloud API 做关键词分流或文本 fallback。 |
@@ -119,7 +119,7 @@ HWLAB 不得用 partial assistant、stdout、transport close、idle timeout 或
HWLAB接入应把 AgentRun result 和 events 投影为 HWLAB 自己的 Turn、Message、Part 和 TraceEvent 事实。AgentRun 是 execution backendWeb Workbench 的会话事实由 HWLAB 的 session/turn/message/trace model 承担;Web、CLI 和 REST snapshot 只能重放该投影,不能分别从 runnerTrace、terminalEvidence、workspace snapshot 或 result polling 生成多套 final response。
PJ2026-0104010803 唯一投影切片要求 HWLAB接入把 projection writer/finalizer 作为 AgentRun -> Workbench facts 的唯一写入口。dispatcher、adapter、compat wrapper、Workbench GET、result polling 和 trace polling 都不能直接写 session summary、assistant message、turn terminal、trace terminal 或 final response。AgentRun terminal result 到达时,HWLAB接入必须以幂等 projection commit 同步更新 assistant message/part final text、turn terminal、trace terminal event、session running=false 和 session summary;若暂时不能提交,必须暴露 projection lag/blocker,而不是让不同 read path 各自显示 completed 或 running
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 是 HWLAB接入中 AgentRun -> Workbench facts 的唯一专项规格。dispatcher、adapter、compat wrapper、Workbench GET、result polling 和 trace polling 都不能直接写 session summary、assistant message、turn terminal、trace terminal 或 final response;它们只能把 normalized facts 交给 projection writer/finalizer,或通过 read model 重放 durable projection。AgentRun terminal result 到达时,终态提交、checkpoint、diagnostic 和重启恢复语义以专项 SPEC 为准
同一次用户提交、steer 或 retry 应在 admission 时生成稳定 turnId、traceId、userMessageId 和 assistantMessageId。初发 UI 可以基于这些标识做 optimistic 展示;AgentRun events/result 到达后必须用同 ID 确认或更新对应 message/part/turn/trace,而不是创建另一条会话消息。页面刷新、session 切换、SSE 重连和 CLI inspect/result 都必须恢复同一组标识和同一语义结果。
@@ -75,7 +75,7 @@ Web工作台负责 HWLAB 登录后的浏览器主入口,使用户能够在同
| 正式公开入口 | 目标 node/lane 在 YAML 中声明的 Cloud Web public URL,用作用户访问、Playwright 验收、文档说明和故障复现入口。 |
| Workbench Server State | Web 工作台从 REST snapshot、SSE event、trace page 和 submit optimistic 归一化得到的服务端事实缓存。 |
| Timeline Projection | 只从 messages、parts、turn status 和 trace events 派生用户可见 timeline row 的渲染投影,不发请求也不写事实状态。 |
| 唯一投影 | PJ2026-0104010803 定义的 Workbench 状态链路:AgentRun 执行事实只经 HWLAB projection writer/finalizer 写入 durable Workbench factsREST、SSE、CLI、fake-server 和 Web 前端只消费该投影。 |
| 唯一投影 | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的状态链路:AgentRun 执行事实只经 HWLAB projection writer/finalizer 写入 durable Workbench factsREST、SSE、CLI、fake-server 和 Web 前端只消费该投影。 |
| 初发刷新一致性 | 同一 prompt 在初次发送、切换 session 后回到该 session、刷新页面和 SSE 重连后,都以同一 userMessageId、assistantMessageId、turnId 和 traceId 还原同一语义结果。 |
| 浏览器回归验证 | 使用 Playwright 在真实浏览器中验证 Workbench 用户可见行为、状态投影和 Trace 阅读正确性的前端端到端单元测试;测试过程使用本地 mock server,不依赖实时 Cloud API、AgentRun、HWPOD 或其他运行组件。 |
| 真实采集 fixture | 从目标 node/lane 的受控样本采集 Workbench REST、SSE、conversation、session、turn 和 trace 响应,经稳定伪 ID 映射与敏感字段脱敏后,用于浏览器回归验证的数据集。 |
@@ -201,69 +201,11 @@ flowchart LR
浏览器回归验证的数据流必须保证:fixture 优先来自目标 node/lane 的真实受控样本;脱敏后保留 conversationId、sessionId、turnId、traceId、messageId 和 sourceSeq 之间的关系;mock server 只重放和变形这些事实,不成为新的业务事实来源;D601 远程 Playwright route 只负责执行与截图 artifact 回传,功能正确性仍由 Web工作台规格定义。
### 5.4 PJ2026-0104010803 唯一投影切片
### 5.4 PJ2026-0104010803 Workbench唯一投影专项
```mermaid
flowchart LR
subgraph AgentRun[AgentRun 执行事实]
RUN[run]
CMD[command]
EV[events/result]
RUN --> CMD
CMD --> EV
end
subgraph HWLAB[HWLAB durable projection]
WR[WorkbenchProjectionWriter]
FIN[WorkbenchTurnFinalizer]
FACT[(session / message / part / turn / trace facts)]
RM[WorkbenchReadModel]
BUS[projection commit event]
WR --> FACT
FIN --> FACT
FACT --> RM
FACT --> BUS
end
subgraph Clients[Workbench consumers]
REST[REST GET snapshot]
SSE[SSE /v1/workbench/events]
RED[Web reducer]
CLI[CLI renderer]
FAKE[fake-server fixture]
RM --> REST
BUS --> SSE
REST --> RED
SSE --> RED
REST --> CLI
REST --> FAKE
end
EV --> WR
```
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 是 Workbench 状态投影的唯一专项规格,集中定义 durable facts schema、`WorkbenchProjectionWriter``WorkbenchProjectionFinalizer``WorkbenchFactsStore``WorkbenchReadModel`、terminal commit、cloud-api 重启恢复、GET 纯读和代码引用规则。
PJ2026-0104010803 的唯一投影边界是:AgentRun run、command、events 和 result 是执行事实;HWLAB `WorkbenchProjectionWriter` / `WorkbenchTurnFinalizer` 是唯一写入者;`WorkbenchReadModel` 是唯一读模型SSE 是 projection commit 后的实时通知;Web reducer、CLI render 和 fake-server fixture 都只消费同一 durable projection。GET 路径只能读取 projection 并暴露 `projectionStatus``lastProjectedSeq``sourceRunId``blocker` 或等价诊断字段,不得隐藏调用 AgentRun、Code Agent 或内部 manager 做 sync、repair、finalize 或补事件
```mermaid
sequenceDiagram
participant User
participant Web as Cloud Web
participant API as HWLAB API
participant AR as AgentRun
participant Writer as WorkbenchProjectionWriter
participant Read as WorkbenchReadModel
participant SSE as Workbench SSE
User->>Web: submit prompt
Web->>API: POST turn admission
API-->>Web: 202 turnId/traceId/messageIds
API->>AR: create run/command
AR-->>Writer: event/result facts
Writer->>Writer: commit message/part/turn/trace/session facts atomically
Writer-->>SSE: projection commit event
Web->>Read: GET session/messages/turn/trace snapshot
SSE-->>Web: message.updated / turn.updated / trace.events.appended
Read-->>Web: same durable facts
Web->>Web: reducer merges by sessionId/messageId/partId/turnId/traceId
```
该时序要求 terminal commit 原子更新 assistant final text/status、turn terminal、trace terminal event、session running=false、summary updated 和 SSE cursor;若写入需重试,必须按幂等键、`projectedSeq``sourceSeq/sourceEventId` 合并,不能让 session rail、message page、turn snapshot 和 trace page 分别推断终态。
Web工作台在本规格中只保留前端消费边界:Cloud Web reducer、selectors、session rail、timeline、composer 和 Trace detail 只能消费该专项定义的 durable projectionSSE 是 projection commit 后的通知和加速;fake-server fixture 只重放同一 REST/SSE 合同。详细架构图、数据流图和关键时序图以专项规格为准,本文不再维护第二份投影架构正文
## 6. 原子需求
@@ -371,7 +313,7 @@ Web工作台应把 REST snapshot、SSE event、submit optimistic、trace paginat
Timeline Projection 只能从 messages、parts、turn status 和 trace events 派生用户可见 rows。Trace detail 只消费 TraceEventPagesession rail 只消费 session list 和 turn summarycomposer 只消费当前 route/selected session 与明确 running turn。组件、trace polling、submit/cancel 回调不得直接写 messages、final response 或 trace authority。
PJ2026-0104010803 唯一投影切片要求 Web 工作台把 `sessionId``messageId``partId``turnId``traceId` 作为 reducer 合并键。REST snapshot、SSE event、submit optimistic 和 trace pagination 的任何 late response 都只能更新其自身 key 对应的事实,不得清空当前 selected session、覆盖已存在 message page、或用 list summary/localStorage/workspace snapshot 重建当前 timeline。running trace 在 terminal 前收到 `hasMore=false` 只表示当前 trace page 暂时追平,不表示 `fullTraceLoaded=true`;后续 SSE 或 REST catch-up 仍必须能追加 terminal event 和 final response。
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 要求 Web 工作台把 `sessionId``messageId``partId``turnId``traceId` 作为 reducer 合并键。REST snapshot、SSE event、submit optimistic 和 trace pagination 的任何 late response 都只能更新其自身 key 对应的事实,不得清空当前 selected session、覆盖已存在 message page、或用 list summary/localStorage/workspace snapshot 重建当前 timeline。running trace 在 terminal 前收到 `hasMore=false` 只表示当前 trace page 暂时追平,不表示 `fullTraceLoaded=true`;后续 SSE 或 REST catch-up 仍必须能追加 terminal event 和 final response。
初发刷新一致性是 Web 工作台的硬约束:同一 prompt 从 admission 开始生成稳定 userMessageId、assistantMessageId、turnId 和 traceId;初发 UI 可以 optimistic 展示这些 ID,但刷新、切换 session、SSE 重连和 REST 补洞必须用同 ID 的 durable message、part、turn 和 trace projection 确认。若 trace events 缺失,只影响 trace detail;主 timeline 的用户消息、assistant final response 和 turn terminal 状态不得因此退化为“思考中”。
@@ -0,0 +1,321 @@
# PJ2026-0104010803 Workbench唯一投影
## 修改历史
| 版本 | 对应 commit id | 更新日期 | 变更说明 |
| --- | --- | --- | --- |
当前正文仍在规格治理草稿中;未定稿前不新增版本号,不为单次编辑追加 `待提交` 版本。
## 正文
## PJ2026-0104010803 Workbench唯一投影需求规格
## 1. 文档控制
| 字段 | 内容 |
| --- | --- |
| 编号 | PJ2026-0104010803 |
| 短名 | Workbench唯一投影 |
| 层级 | L4 专项规格切片 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-18-p0-unique-projection |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md) |
| 关联规格 | [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版:正文只保留 Workbench 唯一投影的稳定使命、范围、术语、系统边界、内部分工和原子需求。
## 2. 目的和范围
### 2.1 目的
Workbench唯一投影负责把 AgentRun 执行事实收敛成 HWLAB 自有的 durable Workbench facts,使 Web、CLI、REST、SSE、fake-server 和浏览器回归都消费同一份可恢复、可分页、可诊断的用户态会话事实。
本专项的目标状态是:AgentRun run、command、event 和 result 只作为执行事实输入;HWLAB 只有 `WorkbenchProjectionWriter``WorkbenchProjectionFinalizer` 写入 Workbench facts;所有 `GET /v1/workbench/*` 和兼容读路径都只通过 `WorkbenchReadModel` 读取,不在读取时调用 AgentRun、Code Agent manager、trace polling、result polling 或 workspace repair 推进事实。
### 2.2 范围内
- AgentRun facts 到 Workbench facts 的标准映射、幂等写入和 terminal commit 语义。
- `session``message``part``turn``trace event``projection checkpoint``projection diagnostic` 的 durable facts schema。
- `WorkbenchFactsStore``WorkbenchProjectionWriter``WorkbenchProjectionFinalizer``WorkbenchReadModel` 的组件边界。
- cloud-api 进程重启、进程内后台任务丢失、慢任务超过短轮询预算后的 durable finalizer 追平语义。
- `GET /v1/workbench/*` 纯读、`/v1/agent/*` compat wrapper 降级和 projection diagnostics 输出要求。
- Web reducer、CLI renderer、fake-server fixture 和 Playwright 回归对同一 durable projection 的消费规则。
- 本专项范围内新增或重构源码文件的 SPEC 头部引用规则。
### 2.3 范围外
- AgentRun run/command/runner job 的执行生命周期事实归 [PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md)。
- HWLAB 到 AgentRun 的 dispatcher、runtime assembly、manual dispatch 和 provider profile 归 [PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md) 及 Agent编排下级规格。
- API path、HTTP schema、错误 envelope 和 route policy 归 [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)。
- Web 布局、组件、浏览器交互和可见 UX 归 [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)。
- 用户身份、权限、额度、账本和 owner visibility 归 [PJ2026-0105 用户管理](PJ2026-0105-user-management.md)。
- CI/CD、GitOps、公开入口、Prometheus 和运行面运维归 [PJ2026-0106 平台运维](PJ2026-0106-platform-ops.md)。
## 3. 术语表
| 术语 | 定义 |
| --- | --- |
| AgentRun facts | AgentRun 产生的 run、command、runner job、event、result、terminalStatus、failureKind、sourceSeq 和 sourceEventId 等执行事实。 |
| Workbench facts | HWLAB 自有的 session、message、part、turn、trace event、checkpoint 和 diagnostic 持久事实,用于用户态 Workbench 展示。 |
| WorkbenchProjectionWriter | 唯一把 normalized AgentRun facts 写成 Workbench facts 的组件;它不处理 HTTP route、鉴权、UI transient state 或兼容 API 输出。 |
| WorkbenchProjectionFinalizer | 以 checkpoint 为驱动的幂等追平组件;可由 submit 后、event 到达、后台恢复或显式 repair mutation 触发,但所有入口调用同一 finalization 逻辑。 |
| WorkbenchFactsStore | durable facts 存储接口,负责幂等 upsert、terminal commit、checkpoint、diagnostic、分页查询和 owner visibility 过滤所需的持久化读写。 |
| WorkbenchReadModel | 唯一读取 Workbench facts 并组装 session rail、session detail、message page、turn snapshot、trace event page 和 projection diagnostics 的读模型。 |
| projection commit | writer/finalizer 对一组 message、part、turn、trace、session summary 和 checkpoint 的一次幂等持久化提交;terminal commit 必须保持用户可见事实一致。 |
| terminal commit | 标记同一 turn 结束的 projection commit,必须原子更新 assistant final text、message/part status、turn terminal、trace terminal event、session running=false、summary 和 SSE cursor。 |
| projectedSeq | HWLAB trace event 和 projection commit 的单调序列,用于 REST 分页、SSE replay、fake-server fixture 和审计;不得与 AgentRun `sourceSeq` 混用。 |
| sourceSeq/sourceEventId | AgentRun event/result 的来源序列或来源事件标识,只作为映射审计字段和幂等输入,不作为 Workbench trace page cursor。 |
| checkpoint | finalizer 已成功投影到某个 sourceRunId/sourceCommandId/sourceSeq 的 durable 位置记录,用于 cloud-api 重启或后台任务丢失后继续追平。 |
| projection diagnostic | 暴露 projection lag、blocker、lastProjectedSeq、sourceRunId、sourceCommandId、updatedAt 和恢复状态的可诊断字段。 |
| compat wrapper | 旧 `/v1/agent/*` 或 conversation path 的兼容包装层;只能调用 `WorkbenchReadModel` 或正式 mutation,不拥有第二套事实写入或 read-through repair。 |
| read-through repair | GET 路径为了让页面“看起来正确”而同步调用 AgentRun、Code Agent manager、workspace repair、trace/result polling 或 billing finalizer 推进事实;本专项禁止该模式。 |
## 4. 系统边界和接口
本规格把 Workbench唯一投影作为客户端、API契约、HWLAB接入和Agent编排之间的状态边界看待;本章只描述输入、输出和责任边界。
| 边界项 | 内容 |
| --- | --- |
| 外部使用者 | Cloud Web、HWLAB CLI、Cloud API route、AgentRun adapter、fake-server 回归和运维诊断。 |
| 外部输入 | AgentRun run/command/event/result facts、turn admission metadata、owner/session visibility、显式 repair mutation、REST/SSE 查询参数。 |
| 受控资源 | Workbench facts、projection checkpoint、diagnostic、projectedSeq、session/message/part/turn/trace 查询模型和 SSE projection commit notification。 |
| 外部输出 | session rail、session detail、message/part page、turn snapshot、trace event page、projection diagnostics、SSE events 和 compat wrapper envelope。 |
| 用户接口 | Cloud Web `/workbench`、同源 `/v1/workbench/*` REST/SSE、HWLAB CLI 的同源 Workbench/API 入口。 |
| 系统边界 | 本专项只定义 Workbench 用户态事实的唯一写入和读取链路;它不定义 AgentRun 执行合同、用户权限策略、Web UI 布局或平台发布机制。 |
## 5. 内部分工与规格索引
| 编号 | 内部模块 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
| --- | --- | --- | --- | --- | --- |
| PJ2026-010401080301 | FactsStore | 本规格 6.1 | durable facts schema、幂等 upsert、terminal commit、checkpoint 和分页读取 | 数据库/runtimeStore、用户管理 visibility | Writer、Finalizer、ReadModel |
| PJ2026-010401080302 | ProjectionWriter | 本规格 6.2 | normalized AgentRun facts 到 Workbench facts 的唯一写入 | HWLAB接入、Agent编排 | ReadModel、SSE、CLI/Web |
| PJ2026-010401080303 | ProjectionFinalizer | 本规格 6.3 | checkpoint 驱动追平、重启恢复和显式 repair mutation 的同一幂等入口 | FactsStore、AgentRun facts source | Writer、diagnostics |
| PJ2026-010401080304 | ReadModel | 本规格 6.4 | session/message/turn/trace/projection diagnostics 的唯一读模型 | FactsStore、用户管理 visibility | REST GET、compat wrapper、CLI、fake-server |
| PJ2026-010401080305 | CompatWrapper | 本规格 6.5 | 旧 `/v1/agent/*` 和 conversation path 到 ReadModel 或正式 mutation 的兼容映射 | API契约、ReadModel | Web/CLI 迁移期兼容 |
| PJ2026-010401080306 | WebServerState | 本规格 6.6 | Web reducer/selectors 只消费 REST/SSE projection,不补写事实 | Web工作台、API契约 | session rail、timeline、composer、trace detail |
| PJ2026-010401080307 | Regression | 本规格 6.7 | 后端红灯、fake-server Playwright、D601 web-probe 和分叉清零验收 | 平台运维、Web工作台 | issue 收口和防回归 |
| PJ2026-010401080308 | CodeReference | 本规格 6.8 | 源码文件头部 SPEC 引用和实现版本追溯 | 规格治理 | 后续实现审计 |
### 5.1 目标架构图
```mermaid
flowchart LR
subgraph AgentRun[AgentRun execution backend]
RUN[run]
CMD[command]
SRC[events / result / sourceSeq]
RUN --> CMD
CMD --> SRC
end
subgraph CloudAPI[HWLAB Cloud API]
AD[AgentRun Adapter: normalize facts]
WR[WorkbenchProjectionWriter]
FIN[WorkbenchProjectionFinalizer]
FS[(WorkbenchFactsStore)]
RM[WorkbenchReadModel]
SSE[SSE publisher]
COMP[Compat wrappers]
AD --> WR
FIN --> WR
WR --> FS
FS --> RM
FS --> SSE
RM --> COMP
end
subgraph Consumers[Projection consumers]
REST[GET /v1/workbench/*]
WEB[Cloud Web reducer/selectors]
CLI[HWLAB CLI renderer]
FAKE[fake-server fixture]
SSEOUT[/v1/workbench/events]
RM --> REST
REST --> WEB
REST --> CLI
REST --> FAKE
SSE --> SSEOUT
SSEOUT --> WEB
end
SRC --> AD
```
目标架构要求 route/auth、adapter、projection writer/finalizer、facts store、read model、SSE publisher 和 compat wrapper 分工清晰。任何 route、GET handler、trace polling、result polling、workspace snapshot 或 front-end reducer 都不能绕过 writer/finalizer 直接改变 Workbench facts。
### 5.2 目标数据流图
```mermaid
flowchart TD
USER[用户 prompt/steer/retry/cancel] --> ADMISSION[Turn admission]
ADMISSION --> IDS[stable turnId traceId userMessageId assistantMessageId]
ADMISSION --> AR[AgentRun run/command]
IDS --> WR0[ProjectionWriter: admission facts]
AR --> EV[AgentRun events/result]
EV --> NORM[normalize AgentRun facts]
NORM --> FIN[ProjectionFinalizer]
FIN --> WR[ProjectionWriter]
WR0 --> TX[projection commit]
WR --> TX
TX --> FACTS[(Workbench facts + checkpoint + diagnostics)]
FACTS --> RM[WorkbenchReadModel]
FACTS --> BUS[SSE projection commit]
RM --> SNAP[REST snapshot / pages]
BUS --> STREAM[SSE events]
SNAP --> RED[Web reducer / CLI / fake-server]
STREAM --> RED
```
数据流必须保证:admission 只生成稳定标识和初始 factsAgentRun facts 必须先归一化,再由 writer/finalizer 进入 projection commitREST snapshot 和 SSE event 只能重放 durable factsdiagnostic 明确表达 lag/blocker,不能让读取路径隐式修复事实。
### 5.3 terminal commit 关键时序图
```mermaid
sequenceDiagram
participant AR as AgentRun
participant Adapter as AgentRun Adapter
participant Finalizer as ProjectionFinalizer
participant Writer as ProjectionWriter
participant Store as FactsStore
participant SSE as SSE Publisher
participant Read as ReadModel
participant Web as Web/CLI/fake-server
AR-->>Adapter: terminal result + events + sourceSeq
Adapter-->>Finalizer: normalized facts
Finalizer->>Writer: finalize sourceRunId/sourceCommandId
Writer->>Store: atomic terminal commit
Store-->>Writer: projectedSeq + checkpoint
Writer-->>SSE: projection commit notification
Web->>Read: GET session/messages/turn/trace
Read->>Store: read only
Read-->>Web: same terminal facts + diagnostics
```
terminal commit 必须在同一幂等提交内更新 assistant final text、message/part terminal status、turn terminal、trace terminal event、session running=false、summary updated、projection checkpoint 和 SSE cursor。若提交失败或暂时无法完成,只能暴露 projection lag/blocker;不得让 session rail 显示 completed、message page 显示 running、turn snapshot 显示 failed 或 trace page 缺 terminal 这类互相矛盾状态。
### 5.4 cloud-api 重启恢复时序图
```mermaid
sequenceDiagram
participant Boot as cloud-api boot/background scheduler
participant Store as FactsStore
participant AR as AgentRun facts source
participant Finalizer as ProjectionFinalizer
participant Writer as ProjectionWriter
participant Read as ReadModel
Boot->>Store: load open checkpoints / lagging commands
Store-->>Boot: sourceRunId/sourceCommandId/lastProjectedSeq
Boot->>Finalizer: resume checkpoint
Finalizer->>AR: fetch events/result after source checkpoint
AR-->>Finalizer: source facts or still-running status
Finalizer->>Writer: idempotent catch-up commit
Writer->>Store: update facts/checkpoint/diagnostic
Read->>Store: read only snapshots
Store-->>Read: caught-up facts or explicit lag/blocker
```
重启恢复要求 finalizer 不依赖进程内 90s 轮询作为唯一推进机制。进程内任务丢失、cloud-api 重启或慢任务超过短轮询预算后,finalizer 必须能从 durable checkpoint 找回需要追平的 sourceRun/sourceCommand,并以同一 writer 逻辑提交或记录 blocker。
## 6. 原子需求
### 6.1 WB-PROJ-REQ-001 durable facts store
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-001 | FactsStore | PJ2026-010401080301 FactsStore | [用户管理](PJ2026-0105-user-management.md)、[API契约](PJ2026-010403-api-contract.md) |
Workbench facts store 应持久化 session、message、part、turn、trace event、projection checkpoint 和 projection diagnostic,使 Workbench 用户态事实可在 cloud-api 重启、进程内任务丢失或后台 finalizer 重跑后恢复。
Facts schema 至少包含以下事实:
| fact | 必需字段 | 职责边界 |
| --- | --- | --- |
| session | sessionId/conversationId/threadId/projectId/workspaceId/owner/status/running/currentTurnId/summary/updatedAt | 会话可见性、rail 摘要和当前 turn 指针;不保存 provider Secret 或完整 prompt 原文之外的敏感负载。 |
| message | messageId/sessionId/role/status/turnId/createdAt/updatedAt | timeline message 事实;assistant final text 通过 part 表达。 |
| part | partId/messageId/type/status/text/tool/error/traceRef/order | 文本、工具、错误和 trace 摘要的可组合展示事实。 |
| turn | turnId/sessionId/traceId/status/terminal/failureKind/sourceRunId/sourceCommandId/messageIds/startedAt/finishedAt | 一次用户提交、steer、retry 或 cancel 的生命周期事实。 |
| trace event | traceId/projectedSeq/sourceSeq/sourceEventId/type/status/timestamp/redactedPayload | Workbench trace page 的分页事实;projectedSeq 是唯一 cursor。 |
| checkpoint | sourceRunId/sourceCommandId/lastSourceSeq/lastProjectedSeq/status/updatedAt | finalizer 追平位置和幂等边界。 |
| diagnostic | sessionId/turnId/traceId/projectionStatus/lag/blocker/sourceRunId/sourceCommandId/updatedAt | GET 和运维可见的 projection 状态,不推进事实。 |
Facts store 必须支持幂等 upsert、terminal commit、projection checkpoint、diagnostic update 和按 owner visibility 过滤的分页查询。`agent_sessions.session_json` 可作为迁移期 metadata 来源,但不得继续承载业务 projection 真相。
### 6.2 WB-PROJ-REQ-002 projection writer
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-002 | Writer | PJ2026-010401080302 ProjectionWriter | [HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Agent编排](PJ2026-0102-agent-orchestration.md) |
WorkbenchProjectionWriter 应作为唯一写入口,把 admission facts 和 normalized AgentRun facts 转换为 durable Workbench facts。Writer 不负责 HTTP route、鉴权、AgentRun fetch、UI transient state、旧 API envelope 或测试 fixture。
Writer 必须使用稳定幂等键写入 messageId、partId、turnId、traceId、sourceRunId、sourceCommandId、sourceSeq/sourceEventId 和 projectedSeq。重复 event、重放 result、重启恢复或 repair mutation 不得创建重复 assistant message、重复 terminal event 或冲突 session summary。
### 6.3 WB-PROJ-REQ-003 projection finalizer
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-003 | Finalizer | PJ2026-010401080303 ProjectionFinalizer | [HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[AgentRun核心](PJ2026-010201-agentrun-core.md) |
WorkbenchProjectionFinalizer 应以 checkpoint 为驱动追平 AgentRun facts。submit 后、event arrival 后、后台恢复和显式 repair mutation 可以触发 finalizer,但这些入口必须调用同一幂等 finalization 逻辑。
Finalizer 不得伪造 terminal、不取消 AgentRun、不用日志尾部推断 completed,也不得让 GET route 临时同步执行 finalization。若 AgentRun 事实暂不可取或映射失败,finalizer 应写入 diagnostic blocker,保留 retry 所需 sourceRun/sourceCommand/checkpoint。
### 6.4 WB-PROJ-REQ-004 read model and pure GET
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-004 | ReadModel | PJ2026-010401080304 ReadModel | [API契约](PJ2026-010403-api-contract.md)、[Web工作台](PJ2026-010401-web-workbench.md) |
WorkbenchReadModel 应作为唯一读模型,从 durable facts 组装 session list、session detail、message page、turn snapshot、trace event page 和 projection diagnostics。Read model 只读 facts store,不调用 AgentRun、Code Agent manager、legacy conversation manager、billing finalizer、workspace repair 或 trace/result polling。
`GET /v1/workbench/*` 必须纯读。若 projection 滞后,响应应输出 `projectionStatus``lastProjectedSeq``sourceRunId``sourceCommandId``blocker` 或等价 diagnostic 字段,不能在 GET 内做 read-through repair。
### 6.5 WB-PROJ-REQ-005 compat wrapper
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-005 | CompatWrapper | PJ2026-010401080305 CompatWrapper | [API契约](PJ2026-010403-api-contract.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md) |
迁移期 `/v1/agent/turns/*``/v1/agent/traces/*`、conversation detail、result polling 和 legacy conversation path 可以作为 compat wrapper 暂存,但只能调用 WorkbenchReadModel 或正式 mutation。Compat wrapper 不得拥有第二套 session/message/turn/trace 写入逻辑,不得在读取时同步 finalizer,也不得用 result cache 或 trace tail 组装另一份 final response。
旧路径返回的 envelope 可以保留 legacy 字段名,但字段值必须来自同一 Workbench facts。若无法映射,应返回结构化 incompatibility/blocker,而不是回退到旧 manager 或空 stub。
### 6.6 WB-PROJ-REQ-006 Web server-state single path
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-006 | Web单路径 | PJ2026-010401080306 WebServerState | [Web工作台](PJ2026-010401-web-workbench.md)、[API契约](PJ2026-010403-api-contract.md) |
Cloud Web 应把 REST snapshot、SSE projection commit、trace event page 和 submit optimistic ids 归一化到同一 server-state/reducer/selectors。UI 组件只消费 selectors;组件、trace polling、result polling、localStorage、workspace snapshot 或 session list summary 不得直接写 final response、message terminal、turn terminal 或 trace authority。
SSE 只作为 projection commit 后的通知和加速,不是事实来源。SSE 断线、丢事件或重连后,Web 只能通过同一 REST snapshot 与 trace page 补洞。running trace 在 terminal 前 `hasMore=false` 只表示当前页追平,不得设置永久 `fullTraceLoaded=true`
### 6.7 WB-PROJ-REQ-007 regression and validation
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-007 | 回归验收 | PJ2026-010401080307 Regression | [Web工作台](PJ2026-010401-web-workbench.md)、[平台运维](PJ2026-0106-platform-ops.md) |
Workbench唯一投影必须有后端和浏览器两层回归:后端用 Workbench-only HTTP 用例证明 submit 后不访问旧 `/v1/agent/turns` 或 result polling 也能自然 completeddurable recovery 用例证明进程内 sync 丢失或 cloud-api 重启后 finalizer 能从 checkpoint 追平;terminal atomicity 用例证明 session rail、session detail、messages、turn snapshot 和 trace event page 不出现 running/completed 组合矛盾。
fake-server Playwright 应使用目标 node/lane 的真实采集脱敏 fixture,覆盖 session 切换、刷新、SSE 断线重连、REST 补洞、trace 分页和 terminal final response。D601 v0.3 public origin web-probe 应验证不切 session、不刷新页面、fresh deep link 和多观察者场景都通过同一 read model 收敛。
### 6.8 WB-PROJ-REQ-008 code reference rule
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-008 | 代码引用 | PJ2026-010401080308 CodeReference | [规格治理](spec-governance.md) |
本专项范围内新增或重构的核心源码文件,文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如:
```text
SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-18-p0-unique-projection
```
同一文件同时承载 API契约、HWLAB接入、Web工作台或 Agent编排职责时,应在同一头部追加对应 SPEC 编号与实现引用版本。实现文件不得只写 issue 编号、`latest``current`。自动生成文件、第三方 vendored 文件、纯配置、锁文件和无法承载注释头的二进制产物可例外,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC。
## 7. 过程控制
本规格的执行证据保留在对应 GitHub 执行 issue、PR、web-probe 报告和 Playwright artifact 中;规格正文不承载长证据、运行日志或一次性排障流水。
本专项关闭前,执行 issue 必须回写以下证据:专项 SPEC commit、后端写点/读点清单、旧路径最终状态、PR、D601 v0.3 发布证据、fake-server Playwright 结果、public origin web-probe 的 script SHA/runDir/report SHA/截图 SHA,以及父级 Web/API/HWLAB接入/Agent编排规格是否仍与实现一致。
@@ -65,8 +65,8 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
| TraceEventPage | 按 traceId 和 cursor/seq 分页查询 trace events 的 RESTful page;只表达 trace 明细,不决定主 timeline 的 final response。 |
| Message/Part | Web 和 CLI 共同渲染会话 timeline 的持久消息事实;message 表达角色、父子关系和终态摘要,part 表达文本、工具、文件、错误、trace 摘要等可组合内容。 |
| EventStream | Cloud Web origin 下的 SSE 实时入口,用于推送 server.connected、session、turn、message、part、trace 和 workspace lifecycle 事件。 |
| WorkbenchProjectionWriter | 把 AgentRun run、command、event 和 result 转换为 HWLAB durable Workbench facts 的唯一写入组件。 |
| WorkbenchReadModel | 从 durable Workbench facts 组装 session detail、message page、turn snapshot、trace event page 和 session rail summary 的唯一读模型。 |
| WorkbenchProjectionWriter | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的唯一写入组件,把 AgentRun run、command、event 和 result 转换为 HWLAB durable Workbench facts。 |
| WorkbenchReadModel | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的唯一读模型,从 durable Workbench facts 组装 session detail、message page、turn snapshot、trace event page 和 session rail summary。 |
| 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。 |
@@ -95,40 +95,11 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
目标后端模块应至少拆分为 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 factscompat wrapper 只提供旧 path 到新资源的兼容映射,不拥有第二套业务事实。
### 5.1 AgentRun 到 Workbench 唯一投影数据流
### 5.1 Workbench唯一投影 API 边界
```mermaid
flowchart LR
AR[AgentRun run/command/events/result] --> AD[AgentRun adapter]
AD --> PW[WorkbenchProjectionWriter]
PW --> FACT[(Workbench durable facts)]
FACT --> RM[WorkbenchReadModel]
FACT --> SSE[SSE event publisher]
RM --> GET[REST GET /v1/workbench/*]
SSE --> ES[GET /v1/workbench/events]
GET --> WEB[Web/CLI/fake-server consumers]
ES --> WEB
```
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 集中定义 AgentRun facts 到 Workbench durable facts 的目标架构、数据流、terminal commit 时序和 cloud-api 重启恢复时序。API契约在本文只保留接口边界:`GET /v1/workbench/*` 只读取 `WorkbenchReadModel`SSE 只发布 projection commit notificationcompat wrapper 只能调用同一 read model 或正式 mutation。
API契约要求 `GET /v1/workbench/*` 只读取 `WorkbenchReadModel`若 AgentRun 事实已经 terminal 但 Workbench projection 尚未追平,GET 响应应暴露 `projectionStatus``lastProjectedSeq``sourceRunId``sourceCommandId``blocker` 或等价诊断字段;不得在 GET 中同步调用 AgentRun、Code Agent manager、legacy conversation manager、billing finalizerworkspace repair 来推进事实
```mermaid
sequenceDiagram
participant AR as AgentRun
participant Writer as ProjectionWriter
participant DB as Durable Facts
participant RM as ReadModel
participant GET as REST GET
participant SSE as SSE
AR-->>Writer: sourceEventId/sourceSeq/result
Writer->>DB: idempotent commit projectedSeq
Writer-->>SSE: projection commit notification
GET->>RM: query session/messages/turn/trace
RM->>DB: read only
RM-->>GET: snapshot + projection diagnostics
```
该时序是 PJ2026-0104010803 的后端不变量。读模型、SSE publisher、compat wrapper 和 CLI render 都不能各自解释 terminal、running、final response 或 trace pagination;它们只能重放 durable projection。
若 AgentRun 事实已经 terminal 但 Workbench projection 尚未追平,GET 响应应暴露 `projectionStatus``lastProjectedSeq``sourceRunId``sourceCommandId``blocker` 或等价诊断字段;不得在 GET 中同步调用 AgentRun、Code Agent manager、legacy conversation manager、billing finalizerworkspace repair、trace polling 或 result polling 来推进事实。读模型、SSE publisher、compat wrapper 和 CLI render 都不能各自解释 terminal、running、final response 或 trace pagination;它们只能重放 durable projection
## 6. 原子需求