docs: freeze workbench long reliability specs

This commit is contained in:
Codex
2026-06-20 00:15:06 +00:00
parent 01fcdcc6f9
commit 126271e770
3 changed files with 53 additions and 6 deletions
@@ -19,7 +19,7 @@
| 短名 | Web工作台 |
| 层级 | L2 课题 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-18-r1; PJ2026-0104010803 唯一投影 draft-2026-06-19-p2-terminal-sealed-final-response |
| 实现引用版本 | draft-2026-06-20-p0-long-running-workbench; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
@@ -34,6 +34,8 @@ Web工作台负责 HWLAB 登录后的浏览器主入口,使用户能够在同
本课题的目标状态是:主任务入口优先、诊断信息低噪声、状态反馈及时、桌面和移动端都能直接找到输入区,并且用户可以从基本工作台发起最小 Agent 调用并获得可查询执行状态。Web 工作台与 HWLAB CLI 必须共用同源 API、composer policy 和 trace renderer 语义,使浏览器问题可以通过同一运行端点的 CLI 非视觉复现。
长程可靠 Workbench 是本课题的黄金用例:用户在同一 public origin 内新建或选择 session,发送 `hi` 或等价最小任务,等待真实 Agent turn 运行,看到主消息区 final response 和 Trace terminal,随后刷新页面、切换到其他 session、再回到原 session、多标签页打开同一 deep link,仍看到同一组 sessionId、turnId、traceId、messageId、sealed final response 和 trace page。主 timeline 不等待完整长 Trace 全量拉完;Trace detail、projection diagnostic、transport diagnostic 和性能指标只解释可见性,不拥有主消息 lifecycle 或 final response 写权。
### 2.2 范围内
- 登录后 Cloud Web shell、topbar、导航、工作台路由、页面切换反馈和同源 API 状态展示。
@@ -212,6 +214,17 @@ flowchart LR
Web工作台在本规格中只保留前端消费边界:Cloud Web reducer、selectors、session rail、timeline、composer 和 Trace detail 只能消费该专项定义的 durable projectionSSE 只是 projection commit 后的通知和加速;fake-server fixture 只重放同一 REST/SSE 合同。Web reducer/selectors、Trace renderer、CLI renderer、fake-server 和测试断言不得从 trace tail、message text、tool event、result cache、session summary、list row、workspace snapshot、localStorage 或 elapsed timeout 推断 lifecycle、terminal、running 或 final response。详细架构图、数据流图、关键时序图、0repair 和严禁读侧推理约束以专项规格为准,本文不再维护第二份投影架构正文。
长程可靠 Workbench 的用户可见验收矩阵如下,后续实现和回归验证必须直接引用这些稳定场景,而不是用单次 canary 或局部截图替代。
| 场景 | 权威事实 | 用户可见结果 | 禁止路径 |
| --- | --- | --- | --- |
| 新建 session 并发送最小 prompt | admission 写入稳定 sessionId、turnId、traceId、userMessageId、assistantMessageId | 当前消息区立即显示用户消息、assistant pending 和可追踪 running 状态 | 用 workspace selected snapshot 或本地 stub 伪造 session/message |
| terminal commit 后显示 final response | sealed message/part/turn/trace facts | 主 timeline 显示 sealed final responseTrace detail 显示 terminal | turn polling、SSE gap、trace hydration error 覆盖主正文 |
| 刷新或 fresh deep link | durable session/message/turn/trace projection | 同一 session/turn/trace/message 恢复,composer 可继续操作 | `sessionRepair`、reload 后自动新建 conversation、localStorage truth |
| 切换 session 后返回 | route sessionId 和 read model bucket | 只更新目标 session bucket,不让迟到响应抢 active route | late response 覆盖当前消息区或 session rail |
| 长 Trace 分页 | `projectedSeq` cursor 和 durable terminal 字段 | 首屏消息先可见,Trace 分页继续加载且不丢 terminal | `hasMore=false` 推断 turn terminal 或全量扫描 live trace tail |
| completed/failed/canceled/blocked | sealed terminal result 或 failure result | 每种终态都有主消息 final 或 failure result,并把 transport diagnostic 分仓 | 诊断文案、result cache 或 trace tail 抢占主消息 final |
## 6. 原子需求
### 6.1 CLIENT-WB-REQ-001 工作台框架
@@ -354,7 +367,7 @@ OpenCode 的参照边界是职责结构,不是技术栈照搬。可借鉴的
Web 工作台实现应按职能拆分为 API client、event/SSE client、server-state store、reducer、selectors/projection、trace event projection、composer UI state、session rail UI state 和具体 UI 组件。server-state 模块不得写 UI transient stateUI 组件不得直接合并 REST/SSE 响应;projection 模块不得发请求或写状态。
新增或重构的核心前端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-18-p0-unique-projection; PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-010403 API契约 draft-2026-06-18-r1`,并简述文件职责。实现文件不得只写 issue 编号、`latest``current` 作为规格引用。
新增或重构的核心前端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; PJ2026-010401 Web工作台 draft-2026-06-20-p0-long-running-workbench; PJ2026-010403 API契约 draft-2026-06-20-p0-workbench-pure-read-api`,并简述文件职责。实现文件不得只写 issue 编号、`latest``current` 作为规格引用。
### 6.10 CLIENT-WB-REQ-010 浏览器回归
@@ -370,6 +383,8 @@ mock 数据应优先来自目标 node/lane 的真实受控样本,而不是从
浏览器回归验证至少覆盖以下用户可见路径:切换 session 后主工作区显示 loading 并恢复目标 sessionfresh browser context 深链进入 session 后以同一 message、turn 和 trace 标识还原 timelineSSE 事件丢失或重连后通过 REST snapshot 和 trace page 补洞;session 标签、workspace card、message card、composer 主按钮和 Trace 终态显示 running、completed、failed、canceled 等状态时保持一致;Trace 阅读视图按事件顺序渲染可读 row,正确处理分页、终态、失败、自动展开和终态折叠;深链进入 session 与普通点击 session 走同一 authority path,删除或归档 session 后 deep link 不得复活 archived active tab。
黄金链路回归必须覆盖完整用户流程:新建 session、发送 `hi`、running 可见、final response 可见、Trace terminal 可见、刷新、切换 session、回到原 session、删除或归档。长程链路回归必须使用真实采集脱敏长 Trace fixture,覆盖分页、SSE gap、projection lag、terminal sealed、diagnostic 分仓和截图 artifact。两类回归都必须记录 fixture schema/redaction 版本、capturedFrom、capturedAt、derivedFrom、截图 SHA 或等价 artifact 校验值。
状态投影回归必须覆盖新建 session 后读侧失败的负向用例:用户显式 create mutation 成功并进入新 session 后,即使随后的 session detail、messages、list refresh、SSE 或 route hydrate 返回失败、404、空列表或网络错误,URL、active tab、当前消息区和 composer 仍归属新 session;页面可以展示该 session 的 loading/degraded/blocker,但不得回退到旧 session、清空 active selection、清空 tabs/messages 或显示 `session_required`。这类用例必须作为 fake-server Playwright 红灯保留,线上 web-probe 只做同一 public origin 的原入口验收,不用 repair helper 修正页面后判通过。
状态投影回归还必须覆盖 completed assistant 已 sealed 后的读侧失败负向用例:fixture 中 session messages API 返回 completed final response,随后 turn snapshot、trace event page、SSE 或 realtime diagnostic 失败。主 timeline 的 sealed final response 不变,诊断只显示在详情/感叹号/transport health 区域;Trace detail 延迟返回或分页缺口不得 remount 主消息卡片,也不得重置用户展开/折叠控制。
@@ -19,7 +19,7 @@
| 短名 | Workbench唯一投影 |
| 层级 | L4 专项规格切片 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-19-p2-terminal-sealed-final-response |
| 实现引用版本 | draft-2026-06-20-p0-durable-facts-model |
| 需求规格模板 | [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) |
@@ -232,6 +232,22 @@ sequenceDiagram
重启恢复要求 finalizer 不依赖进程内 90s 轮询作为唯一推进机制。进程内任务丢失、cloud-api 重启或慢任务超过短轮询预算后,boot/background scheduler 必须能从 durable checkpoint 和 running/projecting turn 找回需要追平的 sourceRun/sourceCommand,并以同一 writer 逻辑提交或记录 blocker。GET、SSE、Web 页面、fake-server 和 probe 只能观察恢复状态,不能触发恢复。
### 5.5 durable Workbench facts 对象模型
Workbench durable facts 是唯一投影的持久对象模型。后续实现可以选择关系表、文档表或 runtime store 等价结构,但必须保留下列对象、稳定键和职责边界;旧 `agent_sessions.session_json`、result snapshot、trace tail、compact snapshot 和 workspace/conversation metadata 只能作为迁移输入或诊断来源,不得成为读取路径 lifecycle authority。
| 对象 | 稳定键 | 关键字段 | 生命周期职责 |
| --- | --- | --- | --- |
| `workbench_session` | `sessionId` | `owner`, `projectId`, `workspaceId`, `status`, `running`, `currentTurnId`, `summary`, `updatedAt` | session rail、detail 和 composer 可继续操作的用户态会话事实。 |
| `workbench_message` | `messageId` | `sessionId`, `role`, `turnId`, `status`, `sealedAt`, `createdAt`, `updatedAt` | timeline message 容器;assistant terminal message sealed 后不被 diagnostic 覆盖。 |
| `workbench_part` | `partId` | `messageId`, `type`, `status`, `text`, `tool`, `error`, `finalResponse`, `traceRef`, `order`, `sealedAt` | 主正文、工具、错误、final response 和 trace 摘要的组合事实。 |
| `workbench_turn` | `turnId` | `sessionId`, `traceId`, `status`, `terminal`, `failureKind`, `sourceRunId`, `sourceCommandId`, `startedAt`, `finishedAt`, `sealedAt` | 一次 prompt、steer、retry 或 cancel 的生命周期事实。 |
| `workbench_trace_event` | `traceId` + `projectedSeq` | `sourceSeq`, `sourceEventId`, `type`, `status`, `timestamp`, `redactedPayload` | Trace event page 的唯一分页事实;`projectedSeq` 是 Workbench cursor。 |
| `workbench_projection_checkpoint` | `sourceRunId` + `sourceCommandId` + `turnId` | `lastSourceSeq`, `lastProjectedSeq`, `sourceLatestSeq`, `status`, `attempt`, `nextRetryAt`, `lastError`, `blocker` | finalizer/resume 追平位置、幂等边界和阻塞恢复状态。 |
| `workbench_projection_diagnostic` | `sessionId` + `turnId` + `traceId` | `projectionStatus`, `health`, `lag`, `blocker`, `sourceRunId`, `sourceCommandId`, `lastProjectedSeq`, `updatedAt` | GET、CLI、Web 和运维可见的投影健康诊断;不推进主事实。 |
对象模型必须支持下列 DTO 投影:session rail summary、session detail、message/part page、turn snapshot、trace event page、projection diagnostic 和 transport diagnostic。DTO 可以裁剪字段,但不得合并 authority;例如 trace detail 可展示 `sourceSeq/sourceEventId` 审计信息,主 timeline 的 finalResponse 只能来自 sealed message/part/turn facts。
## 6. 原子需求
### 6.1 WB-PROJ-REQ-001 durable facts store
@@ -363,7 +379,7 @@ Sealed final response 回归必须构造 completed assistant 主正文已经展
本专项范围内新增或重构的核心源码文件,文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如:
```text
SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p2-terminal-sealed-final-response
SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p0-durable-facts-model
```
同一文件同时承载 API契约、HWLAB接入、Web工作台或 Agent编排职责时,应在同一头部追加对应 SPEC 编号与实现引用版本。实现文件不得只写 issue 编号、`latest``current`。自动生成文件、第三方 vendored 文件、纯配置、锁文件和无法承载注释头的二进制产物可例外,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC。
@@ -19,7 +19,7 @@
| 短名 | API契约 |
| 层级 | L2 课题 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-18-r1; PJ2026-0104010803 唯一投影 draft-2026-06-18-p0-unique-projection; PJ2026-01050105 Web鉴权 draft-2026-06-18-p0-auth |
| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; 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) |
| 规格治理索引 | [规格治理](spec-governance.md) |
@@ -105,6 +105,22 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
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,而不是在读侧选择一个优先级最高的事实源。
### 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。 |
| 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 状态。 |
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 只能观察结果。
## 6. 原子需求
### 6.1 CLIENT-API-REQ-001 同源路由
@@ -186,7 +202,7 @@ Trace resource 必须支持按事件位置继续读取,例如 `sinceSeq` / `cu
所有 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 和下一步建议。
新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-18-p0-unique-projection; PJ2026-010403 API契约 draft-2026-06-18-r1; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0`,并简述文件职责。实现文件不得只写 issue 编号、`latest``current` 作为规格引用。
新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; 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 资源与管理接口