docs: define workbench aggregate event stream spec (#836)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
| 短名 | Web工作台 |
|
||||
| 层级 | L2 课题 |
|
||||
| 状态 | 已生效 |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-long-running-workbench; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p0-passive-web-probe-observer; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-24-p0-no-ui-timing-fabrication; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-long-running-workbench; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p0-passive-web-probe-observer; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-24-p0-no-ui-timing-fabrication; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery; draft-2026-06-24-p0-aggregate-event-stream |
|
||||
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
|
||||
| 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) |
|
||||
| 规格治理索引 | [规格治理](spec-governance.md) |
|
||||
@@ -34,7 +34,7 @@ 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 写权。
|
||||
长程可靠 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 写权。trace/timeline 顺序、完成行位置、terminal sealed duration 和 SSE replay 必须来自唯一投影的 aggregate event stream revision,不能由浏览器 arrival order、trace hydration 顺序、session list 刷新或 probe 后处理重排。
|
||||
|
||||
### 2.2 范围内
|
||||
|
||||
@@ -80,6 +80,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 的渲染投影,不发请求也不写事实状态。 |
|
||||
| Aggregate event stream revision | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的 `eventSeq`、`aggregateSeq` 或等价 projection revision;Web reducer 只能用它判断新旧和补洞,不得用网络到达顺序或本地时间重排 terminal/final/timing。 |
|
||||
| 显示层本地 now | 浏览器组件为了展示“最近 X 秒前”和运行中“耗时 X 秒”而读取的当前时间;它只能作为直接渲染输入,不能写回 Server State、投影、session/message/turn lifecycle 或诊断事实,也不能通过平滑、滤波、单调 floor、跳变 cap 或二次缓存伪造一个更好看的时间事实。 |
|
||||
| 唯一投影 | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的状态链路:AgentRun 执行事实只经 HWLAB projection writer/finalizer 写入 durable Workbench facts,REST、SSE、CLI、fake-server 和 Web 前端只消费该投影。 |
|
||||
| sealed final response | 唯一投影 terminal commit 写入的 assistant 主正文、finalResponse、message/turn terminal status 和 sealed 标记;它是主消息区用户结果的唯一权威,不被后续读侧诊断、trace hydration 失败、turn polling 失败或 SSE gap 覆盖。 |
|
||||
|
||||
+37
-5
@@ -19,7 +19,7 @@
|
||||
| 短名 | Workbench唯一投影 |
|
||||
| 层级 | L4 专项规格切片 |
|
||||
| 状态 | 已生效 |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery; draft-2026-06-22-p1-workbench-redis-derived-cache; draft-2026-06-24-p0-no-ui-timing-fabrication |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery; draft-2026-06-22-p1-workbench-redis-derived-cache; draft-2026-06-24-p0-no-ui-timing-fabrication; draft-2026-06-24-p0-aggregate-event-stream |
|
||||
| 需求规格模板 | [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-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md)、[PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) |
|
||||
@@ -35,6 +35,8 @@ Workbench唯一投影负责把 AgentRun 执行事实收敛成 HWLAB 自有的 du
|
||||
|
||||
本专项的目标状态是:AgentRun run、command、event 和 result 只作为执行事实输入;HWLAB 只有 `WorkbenchProjectionWriter`、`WorkbenchProjectionFinalizer` 写入 Workbench facts;cloud-api boot/background scheduler 是 startup/resume 的 authority,负责扫描 durable open checkpoint 和 running/projecting turn 并恢复追平;所有 `GET /v1/workbench/*` 和兼容读路径都只通过 `WorkbenchReadModel` 读取,不在读取时调用 AgentRun、Code Agent manager、trace polling、result polling 或 workspace repair 推进事实。Workbench 必须满足 0repair:页面、GET、SSE、fake-server 和 web-probe 都不得通过 reload、切换 session、`sessionRepair`、`realignFreshSession`、localStorage truth 或 read-through repair 把已经分裂的 route/session/message/trace 状态补成看起来正确。
|
||||
|
||||
Workbench aggregate event stream 是上述唯一投影的提交脊柱。所有 admission、AgentRun event/result、cancel、replay/reprojection 和 diagnostic transition 先归一化为带 `eventSeq`、`aggregateId`、`aggregateSeq`、`turnId`、`traceId`、`sourceRunId`、`sourceCommandId` 和来源幂等键的 append-only 事件,再由同一 projector 写入 message、part、turn、trace、checkpoint、outbox 和 read model。Web、SSE、CLI、fake-server 和 probe 只能消费该 event stream 的投影结果或 cursor replay,不能分别从 trace tail、result envelope、message cache、session list 和浏览器本地状态重新排序。
|
||||
|
||||
AgentRun terminal outbox 和 command result 是 Code Agent turn terminal 的上游权威输入之一。Projection finalizer 必须以 at-least-once、幂等方式消费对应 run/command 的 terminal outbox/result;即使 events page 没有出现 terminal event、cloud-api 曾重启、进程内 poller 丢失或 result sync 曾超时,后台 resume 也必须重新读取 command result authority 并把真实 terminal 通过同一 writer 写入 Workbench facts。用户 cancel、GET trace/detail、Web reload 或 CLI renderer 都不能代替这个写侧恢复。
|
||||
|
||||
Terminal final response 是 Workbench 投影的 sealed 用户结果。Projection writer/finalizer 一旦把 assistant final text、terminal status 和 `sealedAt` 或等价 sealed 标记写入同一 durable terminal commit,主消息区的正文、finalResponse 和 terminal status 就只能由后续同一写侧投影的受控 replay/reprojection 修正;turn polling、trace hydration、SSE gap、realtime timeout、transport close、read model lag 或 compat wrapper 失败只能写入 trace detail、transport diagnostic、projection diagnostic 或 session health,不能覆盖 sealed 主正文。
|
||||
@@ -47,6 +49,7 @@ D601 v0.3 可以在 `hwlab-v03` namespace 内为 `hwlab-workbench-runtime` 使
|
||||
- `session`、`message`、`part`、`turn`、`trace event`、`projection checkpoint` 和 `projection diagnostic` 的 durable facts schema。
|
||||
- `WorkbenchFactsStore`、`WorkbenchProjectionWriter`、`WorkbenchProjectionFinalizer` 和 `WorkbenchReadModel` 的组件边界。
|
||||
- AgentRun events 增量拉取 cursor、projection state、result sync state 和 cloud-api 重启后按 durable cursor 继续投影的语义。
|
||||
- Workbench aggregate event stream 的 append-only 事件 schema、全局 cursor、aggregate cursor、来源幂等键、projector 边界和投影 revision。
|
||||
- cloud-api 进程重启、进程内后台任务丢失、慢任务超过短轮询预算后的 durable finalizer 追平语义。
|
||||
- Terminal final response 的 sealed 字段、diagnostic 分仓和 sealed 后不可被读侧失败覆盖的显示语义。
|
||||
- `GET /v1/workbench/*` 纯读、`/v1/agent/*` compat wrapper 降级和 projection diagnostics 输出要求。
|
||||
@@ -73,11 +76,15 @@ D601 v0.3 可以在 `hwlab-v03` namespace 内为 `hwlab-workbench-runtime` 使
|
||||
| WorkbenchProjectionWriter | 唯一把 normalized AgentRun facts 写成 Workbench facts 的组件;它不处理 HTTP route、鉴权、UI transient state 或兼容 API 输出。 |
|
||||
| WorkbenchProjectionFinalizer | 以 checkpoint 为驱动的幂等追平组件;可由 submit 后、event 到达、后台恢复或显式 checkpoint replay/reprojection 触发,但所有入口调用同一 finalization 逻辑。 |
|
||||
| WorkbenchFactsStore | durable facts 存储接口,负责幂等 upsert、terminal commit、checkpoint、diagnostic、分页查询和 owner visibility 过滤所需的持久化读写。 |
|
||||
| Workbench aggregate event stream | Workbench 投影自己的 append-only 事件流,承载 admission、source event/result、terminal、diagnostic、replay/reprojection 和 cancel transition;它是 trace/timeline 顺序、SSE replay cursor 和 projector revision 的唯一提交序。 |
|
||||
| WorkbenchReadModel | 唯一读取 Workbench facts 并组装 session rail、session detail、message page、turn snapshot、trace event page 和 projection diagnostics 的读模型。 |
|
||||
| checkpoint replay/reprojection | 受控管理入口按已持久化 sourceRun/sourceCommand/checkpoint 重放投影逻辑,用于恢复投影 lag 或阻塞;它只能调用同一 finalizer/writer,不由 GET、Web 页面、SSE 订阅或测试 helper 触发,也不得改变 active session 或 route。 |
|
||||
| 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。 |
|
||||
| sealed final response | terminal commit 写入的 assistant 主正文、finalResponse、message/turn terminal status 和 `sealedAt` 或等价 sealed 标记;它是主消息区用户结果的唯一权威,不参与后续读侧 diagnostic 竞争。 |
|
||||
| eventSeq | Workbench aggregate event stream 的全局单调提交序,用于 SSE replay、审计和 projector recovery;它不等同于 AgentRun sourceSeq,也不由浏览器生成。 |
|
||||
| aggregateId/aggregateSeq | session、turn、trace 或 message 这类 Workbench aggregate 内部的稳定身份和单调序列,用于同一 aggregate 内的 ordering、去重和 revision 判断。 |
|
||||
| projection revision | projector 成功应用到 read model/facts 后产生的 revision,可由 `eventSeq`、`aggregateSeq` 或等价版本字段表达;API/SSE/Redis cache 只能用它判断新鲜度,不能用本地到达顺序替代。 |
|
||||
| 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 重启或后台任务丢失后继续追平。 |
|
||||
@@ -126,6 +133,7 @@ D601 v0.3 可以在 `hwlab-v03` namespace 内为 `hwlab-workbench-runtime` 使
|
||||
| PJ2026-010401080307 | Regression | 本规格 6.7 | 后端红灯、fake-server Playwright、D601 web-probe 和分叉清零验收 | 平台运维、Web工作台 | issue 收口和防回归 |
|
||||
| PJ2026-010401080308 | CodeReference | 本规格 6.8 | 源码文件头部 SPEC 引用和实现版本追溯 | 规格治理 | 后续实现审计 |
|
||||
| PJ2026-010401080309 | DerivedReadCache | 本规格 6.9 | ReadModel 内部 Redis 派生缓存的 authority input、payload、失效和降级边界 | Workbench性能、API契约 | 高频读降尾延迟 |
|
||||
| PJ2026-010401080310 | AggregateEventStream | 本规格 6.10 | Workbench append-only aggregate event stream、cursor replay、projector revision 和顺序权威 | ProjectionWriter、ProjectionFinalizer、FactsStore | ReadModel、SSE、Web、CLI、fake-server、web-probe |
|
||||
|
||||
### 5.1 目标架构图
|
||||
|
||||
@@ -261,24 +269,26 @@ Workbench durable facts 是唯一投影的持久对象模型。后续实现可
|
||||
| `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`, `lastEventAt`, `finishedAt`, `durationMs`, `sealedAt` | 一次 prompt、steer、retry 或 cancel 的生命周期事实;时间字段只由投影写入。 |
|
||||
| `workbench_aggregate_event` | `eventSeq` 或 `eventId` | `aggregateId`, `aggregateSeq`, `sessionId`, `turnId`, `traceId`, `messageId`, `sourceRunId`, `sourceCommandId`, `sourceSeq`, `sourceEventId`, `eventType`, `occurredAt`, `committedAt`, `payloadRef`, `redactedPayload`, `projectionRevision` | append-only event stream;负责排序、幂等、SSE replay 和 projector recovery,不直接作为 Web 主 DTO 绕过 read model。 |
|
||||
| `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。
|
||||
对象模型必须支持下列 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。`workbench_aggregate_event` 是 projector 和 replay 的提交输入,不允许 Web/API/CLI 直接把事件 payload 拼成另一套 timeline。
|
||||
|
||||
运行中和终态 timing DTO 必须保持可审计:`elapsed`、`recent update`、轮次完成耗时和 trace 首尾耗时的用户可见差异只能来自 durable projection 或上游事件时间戳,不能由 Web reducer、组件、ticker、fake-server、web-probe 或 CLI renderer 在读侧修正。前端只允许把 `now - startedAt`、`now - lastEventAt` 或 sealed `durationMs` 格式化成中文文案;不得保存 per-message timing floor、recent age cache、sealed duration cache、monotonic repair state 或后台 tab resume 补偿状态。若这些值在采样中出现归零、非单调、跳秒或和 terminal commit 不一致,系统必须暴露 projection/timing diagnostic 并修 writer/finalizer/read model、SSE/outbox 或 AgentRun source event,而不是在 UI 层滤波。
|
||||
|
||||
|
||||
### 5.6 durable projection outbox 与 reconciler
|
||||
|
||||
Projection outbox 是 durable commit log,与 projection facts 在同一数据库事务提交。outbox 的作用是让 SSE、CLI 和其他消费者从 durable cursor 恢复实时通知,不依赖进程内内存 listener。
|
||||
Projection outbox 是 durable commit notification log,与 projection facts 和 aggregate event stream commit 在同一数据库事务提交。outbox 的作用是让 SSE、CLI 和其他消费者从 durable cursor 恢复实时通知,不依赖进程内内存 listener。aggregate event stream 表达“发生了什么”和顺序权威;outbox 表达“某次投影 commit 可以通知消费者”,二者不得分叉成两套 lifecycle truth。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
AR[AgentRun events/result] --> AD[Adapter normalize]
|
||||
AD --> WR[ProjectionWriter]
|
||||
WR --> TX[(DB transaction: facts + outbox + checkpoint)]
|
||||
WR --> TX[(DB transaction: aggregate events + facts + outbox + checkpoint)]
|
||||
TX --> AEV[aggregate event stream]
|
||||
TX --> FACTS[durable facts]
|
||||
TX --> OUTBOX[durable outbox rows]
|
||||
TX --> CP[checkpoint]
|
||||
@@ -292,7 +302,7 @@ flowchart LR
|
||||
FIN --> WR
|
||||
```
|
||||
|
||||
Outbox 每行至少包含 `outboxSeq`(全局单调)、`traceId`、`sessionId`、`turnId`、`projectedSeq`、`commitType`(event/terminal/checkpoint/diagnostic)、`createdAt` 和可序列化 payload 摘要。SSE 连接建立时先从 durable outbox 按 `afterSeq` 查询历史 commit notification 进行 replay,再切换到 live tail;cloud-api 重启后不需要内存 listener 即可恢复 SSE 输出。
|
||||
Outbox 每行至少包含 `outboxSeq`(全局单调)、`eventSeq`、`aggregateId`、`aggregateSeq`、`traceId`、`sessionId`、`turnId`、`projectedSeq`、`projectionRevision`、`commitType`(event/terminal/checkpoint/diagnostic)、`createdAt` 和可序列化 payload 摘要。SSE 连接建立时先从 durable outbox 按 `afterSeq` 查询历史 commit notification 进行 replay,再切换到 live tail;cloud-api 重启后不需要内存 listener 即可恢复 SSE 输出。
|
||||
|
||||
Reconciler 是后台 worker,消费 outbox 和 checkpoint 驱动 finalizer 追平。它取代旧的请求/轮询式 `syncAgentRunChatResult` 推进模式:AgentRun result sync 只负责拉取/写入 projection source state,事件推进由 outbox/reconciler 管道统一处理。
|
||||
|
||||
@@ -324,6 +334,8 @@ SSE handler 不再直接订阅内存 `traceStore.subscribe`。它只从 durable
|
||||
|
||||
Projection outbox 的 `outboxSeq` 必须全局单调递增,可通过数据库 sequence 或等价机制生成。outbox 行与 projection facts 在同一事务提交,保证 commit notification 与 durable facts 一致。
|
||||
|
||||
Aggregate event stream 必须同时具备 `(eventSeq)` 全局单调约束、`(aggregateId, aggregateSeq)` aggregate 内单调唯一约束和来源幂等唯一约束。来源幂等键至少覆盖 `sourceRunId`、`sourceCommandId`、`sourceEventId` 或等价 source result id;admission、cancel 和 replay/reprojection 这类本地事件必须有稳定 deterministic eventId。任何需要重排、补 terminal 或修 timing 的逻辑都必须追加受控事件并重新投影,不得直接改 read model 或前端 store。
|
||||
|
||||
### 5.9 0读侧推理验收矩阵
|
||||
|
||||
| 层 | 禁止模式 | 验收方式 |
|
||||
@@ -511,8 +523,28 @@ WorkbenchReadModel 可以使用 Redis 派生读缓存降低高频读路径的 Po
|
||||
|
||||
派生缓存不能成为 GET repair 或多来源仲裁路径。缓存 miss 不得触发 AgentRun、result polling、workspace repair、trace polling 或 projection finalizer;缓存 hit 不得掩盖 SQL/schema/nullability bug、projection blocker、`row_scan_failed` 或 facts corruption。测试和负向扫描必须覆盖 cache hit、miss、stale、unavailable、revision mismatch、actor 隔离和 running turn 不长 TTL。
|
||||
|
||||
### 6.10 WB-PROJ-REQ-010 aggregate event stream
|
||||
|
||||
| 编号 | 短名 | 主责模块 | 关联模块 |
|
||||
| --- | --- | --- | --- |
|
||||
| WB-PROJ-REQ-010 | AggregateEventStream | PJ2026-010401080310 AggregateEventStream | [API契约](PJ2026-010403-api-contract.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md)、[Agent编排](PJ2026-0102-agent-orchestration.md) |
|
||||
|
||||
Workbench aggregate event stream 必须成为 Workbench 投影的唯一提交序。所有 admission、normalized AgentRun event、command result、terminal outbox、cancel mutation、diagnostic transition、checkpoint replay 和受控 reprojection 都必须先形成 durable event,再由同一 projector 生成 message、part、turn、trace event、session summary、projection checkpoint、diagnostic、read model cache invalidation 和 SSE outbox。任何直接写 message/status/trace/read cache 而不追加 aggregate event 的路径都属于第二写权。
|
||||
|
||||
每个事件必须携带稳定身份与排序字段:全局 `eventSeq`、`eventId`、`aggregateId`、`aggregateSeq`、`aggregateType`、`sessionId`、`turnId`、`traceId`、可选 `messageId/partId`、`sourceRunId`、`sourceCommandId`、`sourceSeq/sourceEventId`、`eventType`、`occurredAt`、`committedAt`、`projectionRevision` 和脱敏 payload 摘要。`eventSeq` 用于跨 aggregate SSE replay 和审计;`aggregateSeq` 用于同一 session/turn/trace/message 内的顺序;`sourceSeq` 只用于来源审计和幂等,不得作为 Workbench API cursor。
|
||||
|
||||
Projector 必须按 event stream 的提交序更新 read model。terminal event 必须在同一 projector revision 内原子写入 sealed final response、message/part terminal status、turn terminal、trace terminal marker、session running=false、checkpoint 和 outbox notification。terminal revision 之后的 late event、transport diagnostic、trace hydration result、result archive 或 performance diagnostic 只能追加新的 diagnostic/detail revision;不得重新打开 sealed 主消息、把完成行挪到非最后位置、让完成耗时继续增长,或让 trace/timeline 因到达顺序不同而重新排序。
|
||||
|
||||
SSE replay 必须以 event stream/outbox durable cursor 为权威。`/v1/workbench/events?afterSeq=N` 或等价入口只能返回 `eventSeq/outboxSeq > N` 的投影 commit notification,并在 replay 完成后切到同一 durable tail;不得订阅进程内 `traceStore`、浏览器本地 pending queue、result polling 或 session list diff 作为 live truth。客户端收到重复、乱序或缺口时,应按 cursor 触发 REST/read model 补洞和 transport diagnostic;不能在浏览器 reducer 内通过 arrival order 合成最终顺序。
|
||||
|
||||
Timing 字段必须由 aggregate event stream 和 projector 统一产生。`startedAt` 来自 admission/source start event,`lastEventAt` 来自最新已投影活动事件,`finishedAt` 和 `durationMs` 来自 terminal event 或等价 terminal result;browser local now 只参与渲染运行中相对文案。web-probe 若发现 trace 乱序、完成行不是最后、完成耗时和 trace 首尾耗时不一致、终态耗时继续增长或红色 timing finding,根因修复必须回到 event stream/projector/read model/SSE cursor,不得再通过 Web reducer、probe analyzer、fake-server fixture 或 CSS/DOM 文案做补偿。
|
||||
|
||||
迁移实现必须删除旧的多来源仲裁路径。`traceStore.subscribe`、result envelope fallback、session JSON lifecycle、last trace event heuristic、turn polling status priority、localStorage truth、session repair、fake-server 专用重排和 probe 侧完成行修正只能作为负向扫描对象或迁移输入;保留兼容 wrapper 时也必须调用 WorkbenchReadModel 或正式 mutation。负向回归必须构造 source event 乱序、terminal result 先到、trace hydration 晚到、SSE replay gap、cloud-api rolling restart 和浏览器 session 切换样本,证明完成行、final response、duration、trace page 和 session rail 均按 aggregate event stream revision 收敛。
|
||||
|
||||
## 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编排规格是否仍与实现一致。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`。
|
||||
|
||||
web-probe 历史窗口 trace 乱序、完成行非最后、耗时不一致和红色 finding 的架构修复执行 issue 为 [#2055](https://github.com/pikasTech/HWLAB/issues/2055)。阶段跟踪必须以子 issue 为准:P0 SPEC-first [#2057](https://github.com/pikasTech/HWLAB/issues/2057)、P1 event schema/projector [#2058](https://github.com/pikasTech/HWLAB/issues/2058)、P2 read/SSE seq replay [#2059](https://github.com/pikasTech/HWLAB/issues/2059)、P3 Cloud Web trace/timing 补偿清理 [#2060](https://github.com/pikasTech/HWLAB/issues/2060)、P4 web-probe/OTel 验收固化 [#2061](https://github.com/pikasTech/HWLAB/issues/2061)、P5 D601/v03 长程验收与旧路径删除 [#2062](https://github.com/pikasTech/HWLAB/issues/2062)。后续实现必须引用 `draft-2026-06-24-p0-aggregate-event-stream`,并在关闭各阶段 issue 时说明是否仍存在读侧 repair、到达顺序排序、UI timing fabrication 或 probe 侧补偿。
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
| 短名 | API契约 |
|
||||
| 层级 | L2 课题 |
|
||||
| 状态 | 已生效 |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-22-p1-workbench-redis-derived-cache; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-01050105 Web鉴权 draft-2026-06-18-p0-auth |
|
||||
| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-22-p1-workbench-redis-derived-cache; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p2-terminal-outbox-recovery; draft-2026-06-24-p0-aggregate-event-stream; 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-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
|
||||
@@ -76,6 +76,8 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
|
||||
| EventStream | Cloud Web origin 下的 SSE 实时入口,用于推送 server.connected、session、turn、message、part、trace 和 workspace lifecycle 事件。 |
|
||||
| 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。 |
|
||||
| Aggregate event stream | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的 Workbench append-only event stream;API 只能暴露其 projection revision、cursor 和 replay envelope,不得把 source event array 或 result envelope 作为第二 API 事实源。 |
|
||||
| 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。 |
|
||||
@@ -111,7 +113,9 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
|
||||
|
||||
### 5.1 Workbench唯一投影 API 边界
|
||||
|
||||
[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 notification;compat wrapper 只能调用同一 read model 或正式 mutation。
|
||||
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 集中定义 AgentRun facts 到 Workbench durable facts 的目标架构、aggregate event stream、数据流、terminal commit 时序和 cloud-api 重启恢复时序。API契约在本文只保留接口边界:`GET /v1/workbench/*` 只读取 `WorkbenchReadModel`;SSE 只发布 projection commit notification;compat wrapper 只能调用同一 read model 或正式 mutation。
|
||||
|
||||
Workbench SSE/event API 必须按 aggregate event stream/outbox cursor replay。`GET /v1/workbench/events?afterSeq=N` 或等价入口返回的每条 envelope 至少应携带 `eventSeq` 或 `outboxSeq`、`aggregateId`、`aggregateSeq`、`sessionId`、`turnId`、`traceId`、`projectionRevision`、`commitType` 和脱敏 payload 摘要。API 不承诺按网络到达顺序、trace hydration 完成顺序、result polling 返回顺序或 session list 更新时间排序;客户端必须按 cursor/revision 应用,缺口进入 transport diagnostic 和 REST 补洞。
|
||||
|
||||
若 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。
|
||||
|
||||
@@ -130,6 +134,7 @@ Derived read cache 只能作为 WorkbenchReadModel 内部性能优化。`GET /v1
|
||||
| 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 状态。 |
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
| 短名 | Workbench性能 |
|
||||
| 层级 | L3 子课题 |
|
||||
| 状态 | 已生效 |
|
||||
| 实现引用版本 | draft-2026-06-19-p0; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-22-p1-workbench-redis-derived-cache |
|
||||
| 实现引用版本 | draft-2026-06-19-p0; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-22-p1-workbench-redis-derived-cache; PJ2026-0104010803 唯一投影 draft-2026-06-24-p0-aggregate-event-stream |
|
||||
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
|
||||
| 上级规格 | [PJ2026-010605 运维监控](PJ2026-010605-observability-monitoring.md) |
|
||||
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md) |
|
||||
@@ -35,6 +35,8 @@ Workbench性能负责把 HWLAB Cloud Web 工作台中用户直接感知的等待
|
||||
|
||||
本规格的目标状态是:用户从 Web 发起动作后,浏览器、Cloud API、Workbench SSE、trace/read model、AgentRun adapter 和性能观测存储之间拥有同一套低基数性能事件口径;平台运维可以按时间窗口判断 D601 v0.3 Workbench 是否变慢,客户端和 Agent编排可以用同一脱敏 correlation 继续定位,但监控本身不替代业务功能闭环。直接探针、synthetic check、Prometheus histogram、RUM field data 和服务端 request metric 分属不同 metric family;它们可以在同一 dashboard 中并列展示,不能用一个 family 的结果裁判或覆盖另一个 family 的结果。
|
||||
|
||||
Workbench timing 观测必须以唯一投影的 aggregate event stream revision 为业务顺序锚点。web-probe、RUM、dashboard 和 OTel 可以记录“trace 乱序、完成行非最后、耗时不一致、终态耗时继续增长”等 finding,但这些 finding 只能指向 projector/read model/SSE cursor/timing source 的架构缺陷;不得在 probe analyzer、dashboard 聚合、前端 reducer 或 CSS 文案层做重排、平滑、补零、单调修复或完成行位置修正。
|
||||
|
||||
为降低 D601 v0.3 Workbench 高频读路径对远端 durable Postgres 的重复访问压力,`hwlab-v03` namespace 内可以部署 Workbench 专用的 Redis 派生读缓存。该缓存只服务 `hwlab-workbench-runtime` 的 session summary、terminal turn snapshot 和 terminal trace page 等可重建快照;Postgres durable projection 仍是唯一事实源,Redis 命中只影响读路径耗时、`cacheStatus` 诊断和 DB query avoided 指标,不改变 lifecycle、final response、权限或 projection authority。
|
||||
|
||||
相关运维必须按 UniDesk YAML-first ops 设计:scrape target、recording rule、alert rule、dashboard summary、Prometheus 查询 endpoint、采样/保留/阈值和 D601 node/lane 归属都进入 UniDesk owning YAML;受控 UniDesk CLI 只负责读取 YAML、校验结构、渲染计划、apply/status/summary,并通过共享 ops helper 执行。运行面 Kubernetes 对象、Prometheus target 状态和 Grafana/Prometheus 查询结果只能作为观测对象,不得反向成为配置 source of truth。
|
||||
@@ -75,6 +77,7 @@ Workbench性能负责把 HWLAB Cloud Web 工作台中用户直接感知的等待
|
||||
| First visible | 某个 journey 中第一条用户可读消息、工具调用、错误或加载完成主体在 Web 中可见。 |
|
||||
| Full load | 当前 view 所需权威 REST snapshot、必要 trace page、turn status 和 session rail 数据都已到达并完成可见投影。 |
|
||||
| Backend event visible latency | AgentRun backend 事件的 `createdAt` 或源 seq 时间到 Cloud Web visible ack 的耗时。 |
|
||||
| Aggregate event stream revision | Workbench唯一投影写侧提交序,至少由 `eventSeq`、`aggregateSeq`、`projectionRevision` 或等价字段表达;性能观测只能用它关联业务顺序和可见耗时,不得用本地采样到达顺序重排业务事实。 |
|
||||
| 无响应空闲时间 | 从最近一次可证明的 turn 活动到当前观察点的间隔;活动包括 accepted、run/command/runner job 创建、AgentRun event/result 更新、trace/sourceSeq 前进、SSE/REST snapshot 更新、visible ack 或 liveness heartbeat。 |
|
||||
| RUM | 浏览器端 Real User Monitoring,通过 Web Performance API、Navigation Timing、Long Task、SSE 接收和 DOM paint ack 采集真实用户性能。 |
|
||||
| Server-Timing | HTTP 响应头中的阶段耗时摘要,用于把 API 总耗时拆成 read model、DB、AgentRun adapter、projection 等后端阶段。 |
|
||||
@@ -366,7 +369,7 @@ UniDesk CLI 应提供薄 domain 入口,例如 `hwlab nodes observability plan|
|
||||
| --- | --- | --- | --- |
|
||||
| OPS-WBPERF-REQ-006 | 代码引用 | PJ2026-0106050506 代码引用 | [规格治理](spec-governance.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[API契约](PJ2026-010403-api-contract.md) |
|
||||
|
||||
本性能监控能力的实现必须先引用本规格,再进入代码变更。新增或修改的前端、后端、CLI/helper、metrics、RUM、trace adapter 和 dashboard 源码文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-01060505 Workbench性能 draft-2026-06-17-p0; PJ2026-010401 Web工作台 draft-2026-06-17-r0`,并用一句话说明文件职责。
|
||||
本性能监控能力的实现必须先引用本规格,再进入代码变更。新增或修改的前端、后端、CLI/helper、metrics、RUM、trace adapter、web-probe 和 dashboard 源码文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-01060505 Workbench性能 draft-2026-06-19-p0; PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p0-aggregate-event-stream`,并用一句话说明文件职责。
|
||||
|
||||
实现文件不得只写 issue 编号、`latest`、`current` 或“按最新方案”作为规格引用。自动生成文件、第三方 vendored 文件、纯 YAML/config、锁文件和无法承载注释头的二进制产物不要求加源码头部,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC。
|
||||
|
||||
@@ -386,7 +389,7 @@ Workbench 前端、Cloud API 投影层和性能监控不得维护或展示“运
|
||||
|
||||
总 elapsed time 只可作为诊断字段、性能分布统计或长任务说明展示,不能作为 timeout 判定条件、关闭依据、自动重派依据或用户可见失败文案。性能指标应分别记录 `elapsedMs`、`idleMs`、`lastActivityAt`、`lastActivitySeq` 和 `activitySource`,告警和前端退化只使用 idle/no-response 口径。
|
||||
|
||||
Workbench 性能观测必须把“页面可见 timing 是否真实”作为一等指标。web-probe 应采样每个 Code Agent 卡片的 `耗时`、`最近更新`、轮次完成行耗时、trace 首尾耗时和 terminal sealed duration,并输出采样点表与异常 finding。前端、fake-server、CLI renderer 和 analyzer 不得为了让曲线更好看而平滑、滤波、补零、限速、单调修复或用多来源仲裁替换页面真实值;发现归零、非单调、跳秒、终态后继续增长或与 terminal commit 不一致时,应登记为上游 projection/timing 问题并修权威时间源。
|
||||
Workbench 性能观测必须把“页面可见 timing 是否真实”作为一等指标。web-probe 应采样每个 Code Agent 卡片的 `耗时`、`最近更新`、轮次完成行耗时、trace 首尾耗时、terminal sealed duration 和对应 aggregate event stream revision,并输出采样点表与异常 finding。前端、fake-server、CLI renderer、dashboard 和 analyzer 不得为了让曲线更好看而平滑、滤波、补零、限速、单调修复、完成行重排或用多来源仲裁替换页面真实值;发现归零、非单调、跳秒、终态后继续增长、完成行非最后、trace event 顺序和 `eventSeq/aggregateSeq` 不一致或与 terminal commit 不一致时,应登记为上游 projection/timing 问题并修 event stream、projector、read model、SSE cursor 或权威时间源。
|
||||
|
||||
该需求不得削弱功能正确性:terminal result、billing finalize、session owner record、conversation fact 和 trace terminal evidence 仍由最终同步或后续 poll 完成;快速返回只限制单次用户可见 poll 的等待预算,不丢弃 AgentRun 事实、不伪造 final response、不把未完成 turn 标记为完成。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user