docs: 废弃 Workbench 事务投影旧规格

This commit is contained in:
Codex
2026-07-16 19:29:04 +02:00
parent 7bc39c388e
commit 732a9c8d3a
12 changed files with 117 additions and 714 deletions
@@ -145,7 +145,7 @@ Agent编排应原样消费 AgentRun 的 run、command、runner job、event、ter
HWLAB 不应在客户端、adapter 或 prompt 中推断或补造 AgentRun 没有发出的事实。AgentRun 已正确输出时,HWLAB 负责消费和业务映射;AgentRun 合同缺失或行为错误时,应回到 AgentRun 实现与对应 OA 规格修复。
[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 pollinglegacy conversation path 分别读取 AgentRun 并各自推断 session running、assistant final response、turn terminal 或 trace terminal;同一 AgentRun 事实只能形成一份 HWLAB Workbench durable projection
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 要求 Agent编排只把 AgentRun run、command、event、terminal status、failureKind 和 result envelope 发布到 `agentrun.event.v1`,再由 HWLAB mapper direct publish 到 `hwlab.event.v1`。Agent编排不得让 Web、CLI、Workbench GET、trace pollinglegacy conversation path 或 PostgreSQL outbox 建立第二事实权威
Serve/session aggregate authority 要求职责进一步分离:AgentRun 拥有 run、command、runner job、cancel delivery、terminal report 和 execution diagnosticHWLAB Workbench 拥有用户态 session aggregate、input/command fact、message/part、trace/timing、sealed final response 和 projection diagnostic。AgentRun 应暴露稳定 runId、commandId、event/result id、terminal status、failureKind、cancel/no-op 和 stale/blocked diagnostic,使 Workbench input/command fact 能回绑执行事实;AgentRun 不拥有 Workbench message/final/timing 显示权,也不通过旧 conversation/session 路径覆盖 Workbench read model。
@@ -256,7 +256,7 @@ stale lease 不能单独推断 runner lost。runner lost、still running、compl
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| AR-CORE-REQ-007 | 终态Outbox | PJ2026-01020106 终态Outbox | [后端Profile](PJ2026-010204-backend-profile.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) |
| AR-CORE-REQ-007 | 终态Outbox | PJ2026-01020106 终态Outbox | [后端Profile](PJ2026-010204-backend-profile.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) |
runner 对 command terminal、run terminal、final assistant response、failureKind、threadId/turnId 和 terminal artifact 摘要必须使用 durable outbox、retry-until-ack 或等价可恢复提交协议。manager HTTP 短暂不可用时,runner 可以延迟上报,但不能把 terminal fact 只保留在进程内内存或易丢 stdout 中。
@@ -19,7 +19,7 @@
| 短名 | HWLAB接入 |
| 层级 | L2 课题 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-06-17-r0; PJ2026-0104010803 唯一投影 draft-2026-06-19-p1-agentrun-incremental-cursor; draft-2026-06-25-p0-session-warm-runner-contract |
| 实现引用版本 | draft-2026-06-17-r0; draft-2026-06-25-p0-session-warm-runner-contract; PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
@@ -61,7 +61,7 @@ Workbench 多 turn 接入还必须保持 session execution lane。HWLAB adapter
| 手动调度 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 | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的唯一写入组件,在 HWLAB接入中把 AgentRun result envelope 和 events 写成 Workbench session、message、part、turn 和 trace facts。 |
| Workbench事件映射器 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的 direct publish 组件,把 `agentrun.event.v1` 归一化为 `hwlab.event.v1`,不以内联 PostgreSQL 投影或 outbox 作为前置。 |
| 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。 |
@@ -127,11 +127,11 @@ HWLAB接入应消费 AgentRun events、command result、terminal status、failur
HWLAB 不得用 partial assistant、stdout、transport close、idle timeout 或日志尾部推断 completed。`eventsCapped=true`、final assistant 截断或 command 未终态时,HWLAB 应继续读取 AgentRun events/trace,而不是把当前摘要当作完整归档。
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 snapshotresult polling 生成多套 final response。
HWLAB接入应把 AgentRun events 映射并 direct publish 为 `hwlab.event.v1` 的 Turn、Message、Part 和 TraceEvent typed events。AgentRun 是 execution backendKafka 是 Workbench 实时与回放的单一事件权威Web、CLI 和 REST snapshot 不能分别从 runnerTrace、terminalEvidence、workspace snapshotresult polling 或数据库 outbox 生成多套 final response。
[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 为准
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 是 HWLAB接入中 AgentRun -> Workbench 的唯一专项规格。mapper 只负责 `agentrun.event.v1 -> hwlab.event.v1`live SSE 与 refresh replay 都消费 `hwlab.event.v1`,并使用同一 reducer。dispatcher、compat wrapper、Workbench GET、result polling 和 trace polling 不得建立第二写权或替代 Kafka replay
HWLAB 接入消费 AgentRun events 时必须按 Workbench 唯一投影的 durable cursor 执行增量拉取。运行中进度以 `events?afterSeq=<lastSourceSeq>` 和 command/window 过滤后的 normalized facts 为主读源;AgentRun `/result` 只用于终态补全或后台归档,不得作为 running turn 的主读源,也不得因为 `/result` 慢或超时阻断 events projection、Workbench trace 进度或 projection state 推进
HWLAB 接入必须按 AgentRun Kafka event cursor 幂等消费并 direct publish。AgentRun `/result` 只用于终态补全或后台归档,不得作为 running turn 的主读源,也不得因为 `/result` 慢或超时阻断 Kafka event mapping、Workbench trace 进度或 terminal typed event 发布
AgentRun manager rolling 或 runner terminal report delayed 时,HWLAB接入只能消费 AgentRun durable diagnosis、observation facts 和 terminalReportState,并把它们交给 Workbench projection diagnostic。若 AgentRun ledger 暂时 stale、runnerJob observation 尚未恢复或 terminal outbox 尚未提交,HWLAB 应输出 projecting/degraded/stalled/blocker 等可解释状态;不得在 dispatcher、compat wrapper、GET handler、CLI renderer、trace polling 或 Web reducer 中根据 Kubernetes Job phase、stdout、最后一条 event、elapsed timeout 或用户切换 session 推断 completed。
@@ -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; draft-2026-06-25-p0-web-caserun-e2e; draft-2026-06-25-p0-project-management-mdtodo; 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; draft-2026-06-25-p0-serve-session-aggregate-authority; draft-2026-06-25-p0-session-warm-runner-contract; draft-2026-06-27-p0-workbench-read-model-contract; PJ2026-010401080313 Workbench实时权威 draft-2026-07-08-p0-workbench-realtime-authority-v2; draft-2026-07-09-p1-single-step-debug |
| 实现引用版本 | 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-24-p0-no-ui-timing-fabrication; draft-2026-06-25-p0-web-caserun-e2e; PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
@@ -70,7 +70,7 @@ Web工作台负责 HWLAB 登录后的浏览器主入口,使用户能够在同
| 主任务区 | 用户完成主要工作流的区域,包括会话消息和命令输入区。 |
| 命令输入区 | 用户输入新任务、引导运行中任务、取消或重试任务的 Web 控件集合。 |
| 诊断入口 | 用户主动打开的工作台状态详情入口,通常以 topbar 内的小型按钮或状态图标呈现。 |
| Workbench实时调试台 | 独立于真实 Workbench 业务页的调试路由,用 fake fixture 单步驱动 reducer 和 UI 投影,验证高纯度 SSE、统一 sync replay、detail-only 隔离和禁止补洞规则。 |
| Workbench实时调试台 | 独立于真实 Workbench 业务页的调试路由,用 fake fixture 单步驱动 reducer 和 UI 投影,验证高纯度 SSE、Kafka retention replay、detail-only 隔离和禁止补洞规则。 |
| 低噪声展示 | 诊断、trace、状态和辅助信息不抢占主任务区,也不伪装成用户或 Agent 正文。 |
| 响应式工作台 | 同一工作台在桌面和移动端按不同可视空间重排,但仍优先保证任务输入和状态理解。 |
| 同源业务入口 | Cloud Web 与 HWLAB CLI 通过同一 Web origin、相对 REST/JSON API path 和业务标识访问 HWLAB 能力的入口。 |
@@ -92,11 +92,11 @@ 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 revisionWeb reducer 只能用它判断新旧和补洞,不得用网络到达顺序或本地时间重排 terminal/final/timing。 |
| Kafka event revision | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的 Kafka cursor、entity version 或等价 `projectionRevision`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 factsREST、SSE、CLI、fake-server 和 Web 前端只消费该投影。 |
| Serve Session Aggregate Authority | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的会话级权威链路;Web 的 prompt、steer、cancel、retry、run-state、message/part、trace/timing 和 final response 只能消费该 aggregate read model。 |
| session execution lane | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的会话执行通道;Web 只能展示其 read model 和 diagnostic,不从 DOM active card 或本地 pending 状态推断是否复用了 runner。 |
| 实时权威 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的 `agentrun.event.v1 -> hwlab.event.v1 -> live/replay SSE -> reducer` 单一 Kafka 状态链路。 |
| Serve Session Authority | Workbench 会话级 typed event 权威;Web 的 run-state、message/part、trace/timing 和 final response 由同一 live/replay SSE reducer 收敛。 |
| session execution lane | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的会话执行通道;Web 只能展示其 read model 和 diagnostic,不从 DOM active card 或本地 pending 状态推断是否复用了 runner。 |
| sealed final response | 唯一投影 terminal commit 写入的 assistant 主正文、finalResponse、message/turn terminal status 和 sealed 标记;它是主消息区用户结果的唯一权威,不被后续读侧诊断、trace detail 失败、旧 turn polling 失败或 SSE gap 覆盖。 |
| 破坏性投影权 | 删除 session、清空 active session、清空当前消息页、把 composer 改为无 session 或把 session lifecycle 改写为 not-found/archived/deleted 的权力。Web 前端 reducer、selectors、route hydrate、GET/list/detail/messages/SSE consumer 和测试 helper 没有破坏性投影权;只有显式用户 mutation 成功或后端 canonical lifecycle projection 可以改变这些事实。 |
| 读侧推理 | Web、API、CLI、fake-server 或测试根据 trace tail、message text、tool event、result cache、session summary、list row、workspace snapshot、localStorage 或 elapsed timeout 推断 lifecycle、terminal、running 或 final response 的行为;Web工作台禁止该模式。 |
@@ -151,7 +151,7 @@ flowchart TD
C --> A[POST Turn Admission]
A --> O[Optimistic user/assistant message IDs]
A --> E[SSE /workbench/events typed events]
A --> SY[/workbench/sync replay when needed]
A --> SY[/workbench/Kafka replay when needed]
E --> R[Workbench Reducer]
SY --> R
SNAP[Initial snapshot] --> R
@@ -166,7 +166,7 @@ flowchart TD
TD --> UI
```
目标数据流必须保证:提交请求只负责 admission 和稳定标识;主状态只接受 initial snapshot、SSE typed event、统一 `/workbench/sync` replay/delta 和可对账的 optimistic echo。显式 detail/history 只进入 detail 或 diagnostic bucket。晚到响应只能更新其声明的 session、turn、message 或 trace bucket,不能改变当前 active session、active route、当前消息区或 composer。
目标数据流必须保证:提交请求只负责 admission 和稳定标识;主状态只接受 initial snapshot、`hwlab.event.v1` live/replay SSE 和可对账的 optimistic echo。显式 detail/history 只进入 detail 或 diagnostic bucket。晚到响应只能更新其声明的 session、turn、message 或 trace bucket,不能改变当前 active session、active route、当前消息区或 composer。
### 5.2 目标架构图
@@ -268,15 +268,15 @@ flowchart LR
长程 observer 的数据流必须保证:`trans` 只写命令文件和读取产物,不打开入站控制端口;observer 是目标 host 上的客户端进程,不是 Web 服务、daemon API、数据库消费者或平台状态源。控制命令、采样器和后处理分析共享同一份时间戳化 artifact;控制命令改变页面时必须记录为用户意图来源,采样器本身不得通过主动 API 请求、reload、自动点击、session repair 或网络拦截制造新业务事件。
### 5.5 PJ2026-0104010803 Workbench唯一投影专项
### 5.5 PJ2026-010401080313 Workbench实时权威专项
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 是 Workbench 状态投影的唯一专项规格,集中定义 durable facts schema、`WorkbenchProjectionWriter``WorkbenchProjectionFinalizer``WorkbenchFactsStore``WorkbenchReadModel`、terminal commit、sealed final response、cloud-api 重启恢复、GET 纯读和代码引用规则。
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 是 Workbench 状态链路的唯一专项规格,集中定义 direct publish、`hwlab.event.v1`、live SSE、Kafka retention replay、同一 reducer、terminal seal、GET 纯读和代码引用规则。
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。运行中相对时间展示是唯一允许的显示层本地 now 使用场景:`startedAt``lastEventAt``finishedAt` 和 sealed `durationMs` 仍来自 durable projection,浏览器只用本地 now 对这些权威字段做直接格式化,不产生新事实。前端严禁为了掩盖跳变、归零、非单调、投影滞后或后台 tab 抖动而加入平滑、滤波、单调 floor、跳变 cap、二次缓存、最近更新时间重算或“看起来连续”的时间造假;发现此类异常必须暴露 diagnostic 并修 durable projection、read model、SSE/outbox 或上游时间源。详细架构图、数据流图、关键时序图、0repair 和严禁读侧推理约束以专项规格为准,本文不再维护第二份投影架构正文
Web工作台在本规格中只保留前端消费边界:Cloud Web reducer、selectors、session rail、timeline、composer 和 Trace detail 只能消费 initial snapshot 与同一 `hwlab.event.v1` live/replay SSE 合同fake-server fixture 只重放该合同。浏览器不得通过 `/v1/workbench/sync`、业务 REST fan-out、页面轮询、localStorage 或 trace tail 补写主状态。运行中相对时间只格式化事件提供的 canonical 时间字段,不产生新事实;异常必须暴露 diagnostic 并修 mapper、Kafka/SSE 或 reducer,不得恢复 PostgreSQL outbox authority
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 是 Workbench 高纯度 SSE、统一 sync replay、detail-only 隔离、禁止前端多源补洞和单步调试台的专项规格。Web 工作台新增或修改 EventSource、sync replay、detail/history、Colada key、server-state reducer 或 debug fixture 时,必须先遵守该专项的 authority gate、sealed guard、legacy fan-out 禁止路径和 fake SSE 单步验收。
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 是 Workbench 高纯度 SSE、Kafka retention replay、detail-only 隔离、禁止前端多源补洞和单步调试台的专项规格。Web 工作台新增或修改 EventSource、Kafka replay、detail/history、Colada key、server-state reducer 或 debug fixture 时,必须先遵守该专项的 authority gate、sealed guard、legacy fan-out 禁止路径和 fake SSE 单步验收。
[PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md) 是 Workbench 浏览器实时链路、防请求风暴和 freeze/blocker 的专项规格。Web 工作台新增或修改 SSE/EventSource、sync replay、health probe、explicit snapshot/detail/history refresh、timeline row、storage、scroll 或 runtime diagnostic 逻辑时,必须遵守该专项的 typed error、scoped key、queue/single-flight、SSE transport、browser memory policy 和 no-probe-masking 要求。卡死、内存上涨和请求风暴的修复不得落在 web-probe/Playwright 资源削减、自动刷新或 analyzer 降级上;这些探针只能提供证据和红灯。
[PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md) 是 Workbench 浏览器实时链路、防请求风暴和 freeze/blocker 的专项规格。Web 工作台新增或修改 SSE/EventSource、Kafka replay、health probe、explicit snapshot/detail/history refresh、timeline row、storage、scroll 或 runtime diagnostic 逻辑时,必须遵守该专项的 typed error、scoped key、queue/single-flight、SSE transport、browser memory policy 和 no-probe-masking 要求。卡死、内存上涨和请求风暴的修复不得落在 web-probe/Playwright 资源削减、自动刷新或 analyzer 降级上;这些探针只能提供证据和红灯。
长程可靠 Workbench 的用户可见验收矩阵如下,后续实现和回归验证必须直接引用这些稳定场景,而不是用单次 canary 或局部截图替代。
@@ -411,13 +411,13 @@ Web工作台的正式浏览器入口必须来自目标 node/lane YAML 声明的
| --- | --- | --- | --- |
| CLIENT-WB-REQ-008 | 状态投影 | PJ2026-01040108 状态投影 | [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[Agent编排](PJ2026-0102-agent-orchestration.md) |
Web工作台应把 initial snapshot、SSE typed event、统一 `/v1/workbench/sync` replay/delta 和 submit optimistic echo 统一归入 Workbench Server State。显式 trace detail/history 读取只进入 detail 或 diagnostic bucket,不拥有主状态写权。Server State 应按 sessionId、messageId、partId、turnId 和 traceId 归一化保存服务端事实;conversationId、projectId 和 workspaceId 只能作为后端 metadata 或兼容映射字段挂接在对应 session/message 上,不得作为 active 对象、权限判断或恢复路径的 authority。UI transient state 只保存 route、显式选择、composer draft、scroll、展开状态和临时交互状态。
Web工作台应把 initial snapshot、SSE typed event、Kafka retention replay SSE 和 submit optimistic echo 统一归入 Workbench Server State。显式 trace detail/history 读取只进入 detail 或 diagnostic bucket,不拥有主状态写权。Server State 应按 sessionId、messageId、partId、turnId 和 traceId 归一化保存服务端事实;conversationId、projectId 和 workspaceId 只能作为后端 metadata 或兼容映射字段挂接在对应 session/message 上,不得作为 active 对象、权限判断或恢复路径的 authority。UI transient state 只保存 route、显式选择、composer draft、scroll、展开状态和临时交互状态。
Timeline Projection 只能从 messages、parts、turn status 和被主 authority 接受的 trace marker 派生用户可见 rows。Trace detail 只消费 detail/history projectionsession rail 只消费同一 durable projection 的 session summary 和 turn summarycomposer 只消费当前 route/selected session 与明确 running turn。组件、trace polling、submit/cancel 回调不得直接写 messages、final response、turn status 或 trace authority。
[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 和 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 要求 Web 工作台把 `sessionId``messageId``partId``turnId``traceId` 作为 reducer 合并键,并同时检查 `realtimeAuthority`、entity family/id/version、cursor 和 `projectionRevision`。initial snapshot、SSE typed event、sync replay、submit optimistic 和 explicit detail/history 的任何 late response 都只能更新其自身 key 与授权 bucket 对应的事实,不得清空当前 selected session、覆盖已存在 sealed message、或用 list summary/localStorage/workspace snapshot 重建当前 timeline。running trace 在 terminal 前 detail page 收到 `hasMore=false` 只表示 detail page 暂时追平,不表示主 turn 已 terminal;后续 SSE typed event 或 sync replay 仍必须能追加 terminal seal 和 final response。
[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 要求 Web 工作台把 `sessionId``messageId``partId``turnId``traceId` 作为 reducer 合并键,并同时检查 `realtimeAuthority`、entity family/id/version、Kafka cursor 和 `projectionRevision`。initial snapshot、live/replay SSE、submit optimistic 和 explicit detail/history 的任何 late response 都只能更新其自身 key 与授权 bucket 对应的事实,不得清空当前 selected session、覆盖已存在 sealed message、或用 list summary/localStorage/workspace snapshot 重建当前 timeline。
Message page 在刷新、切换 session、SSE 重连和 sync replay 后必须保持同一 turn timeline 顺序:同一轮用户输入应先于对应 assistant/agent terminal,跨轮次按 turn timeline/aggregate seq/事件时间排序,不得按 role、source table、投影写入批次或 `updatedAt desc` 形成 `UUAA``UUUAAA` 等用户消息聚簇。前端不得通过 DOM 后处理或本地排序掩盖 read model 聚簇;若 API 已经聚簇,修复点必须回到 WorkbenchReadModel 或 projection writer。
Message page 在刷新、切换 session、SSE 重连和 Kafka replay 后必须保持同一 turn timeline 顺序:同一轮用户输入应先于对应 assistant/agent terminal,跨轮次按 turn timeline/aggregate seq/事件时间排序,不得按 role、source table、投影写入批次或 `updatedAt desc` 形成 `UUAA``UUUAAA` 等用户消息聚簇。前端不得通过 DOM 后处理或本地排序掩盖 read model 聚簇;若 API 已经聚簇,修复点必须回到 WorkbenchReadModel 或 projection writer。
Session rail 的 title/preview 必须来自同一 durable message/part projection 的脱敏摘要,并随 session list/detail 返回稳定字段。仅当 read model 明确缺失 title/preview 时,UI 才能短暂展示 fallback `Session ses_*`web-probe 与 OTel 必须把 fallback 数量、比例和示例暴露为 projection/read-model 问题,而不是把 fallback 当作正常标题。
@@ -431,11 +431,11 @@ Web 工作台必须把主消息投影、trace detail、session status 和 transp
Web reducer/selectors 必须同时遵守无破坏性投影权。读侧路径中的 `forgetSession``replaceActiveSessionSelection(null)`、清空 messages、清空 tabs、把 composer 降级为 `session_required` 或把 route session 标记为 not-found/archived/deleted,都是 lifecycle mutation,不能由 GET/list/detail/messages/SSE 失败、空响应、404、route hydrate、refreshSessions 或 late response 触发。读侧只能把目标 session 的 loading、degraded、unknown、blocker 或 canonical lifecycle projection 展示出来;若需要删除、归档或失活,必须走后端 lifecycle projection 或用户显式 mutation 的成功结果。
初发刷新一致性是 Web 工作台的硬约束:同一 prompt 从 admission 开始生成稳定 userMessageId、assistantMessageId、turnId 和 traceId;初发 UI 可以 optimistic 展示这些 ID,但刷新、切换 session、SSE 重连和 sync replay 必须用同 ID 的 durable message、part、turn 和 trace projection 确认。若 trace detail events 缺失,只影响 trace detail;主 timeline 的用户消息、assistant final response 和 turn terminal 状态不得因此退化为“思考中”。
初发刷新一致性是 Web 工作台的硬约束:同一 prompt 从 admission 开始生成稳定 userMessageId、assistantMessageId、turnId 和 traceId;初发 UI 可以 optimistic 展示这些 ID,但刷新、切换 session、SSE 重连和 Kafka replay 必须用同 ID 的 durable message、part、turn 和 trace projection 确认。若 trace detail events 缺失,只影响 trace detail;主 timeline 的用户消息、assistant final response 和 turn terminal 状态不得因此退化为“思考中”。
OpenCode 的参照边界是职责结构,不是技术栈照搬。可借鉴的边界包括 route/sessionKey 作为当前 session authority、per-session message/part cache、REST message page 与 optimistic message 通过同一 messageID 合并、SSE delta 只作为实时加速、完整 message/part snapshot 可重建刷新结果。HWLAB 不得继续让 workspace snapshot、trace polling、result polling、list summary 和 localStorage 共同竞争当前消息面板。
状态投影正确性必须能被独立浏览器回归验证覆盖。测试应在同一 Web 构建产物上使用 mock server 或 debug harness 重放真实采集 fixture,断言 session rail、主 timeline、workspace card、composer、message card 和 trace detail 在 session 切换、刷新页面、SSE 断线重连、sync replay 和 trace detail 分页后保持同一组 sessionId、turnId、traceId、messageId 与终态语义;conversationId/projectId/workspaceId 只可作为 metadata 被展示或调试,不得改变通过条件。测试不得依赖 live AgentRun、Cloud API、HWPOD、数据库或 Kubernetes 状态作为通过条件。
状态投影正确性必须能被独立浏览器回归验证覆盖。测试应在同一 Web 构建产物上使用 mock server 或 debug harness 重放真实采集 fixture,断言 session rail、主 timeline、workspace card、composer、message card 和 trace detail 在 session 切换、刷新页面、SSE 断线重连、Kafka replay 和 trace detail 分页后保持同一组 sessionId、turnId、traceId、messageId 与终态语义;conversationId/projectId/workspaceId 只可作为 metadata 被展示或调试,不得改变通过条件。测试不得依赖 live AgentRun、Cloud API、HWPOD、数据库或 Kubernetes 状态作为通过条件。
状态投影回归还必须覆盖 sealed final responsecompleted assistant 正文已经显示后,turn snapshot、trace event page、SSE 或 realtime diagnostic 返回 timeout/500/gap/close 时,主消息正文和终态保持不变,诊断只进入 trace detail、transport diagnostic、session health 或消息详情入口。测试必须用用户可见 DOM 断言,不通过内部 store 或 localStorage 判定通过。
@@ -449,7 +449,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-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` 作为规格引用。
新增或重构的核心前端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority; 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 浏览器回归
@@ -463,13 +463,13 @@ mock 数据应优先来自目标 node/lane 的真实受控样本,而不是从
合成 fixture 只能补足真实样本难以稳定覆盖的边界条件,例如延迟响应、SSE 断线、分页缺口、列表缺少当前选中项、可选字段格式异常、空集合和特定 HTTP 错误。每个合成 fixture 必须标明 `derivedFrom``syntheticReason`,不得替代可从真实运行面采集的常规会话、完成态、失败态或 Trace 数据。
浏览器回归验证至少覆盖以下用户可见路径:切换 session 后主工作区显示 loading 并恢复目标 sessionfresh browser context 深链进入 session 后以同一 message、turn 和 trace 标识还原 timeline;SSE 事件重复、乱序、丢失或重连后通过 SSE replay 或统一 `/v1/workbench/sync` replay 收敛,不触发旧 trace/session/turn 多端点补洞;session 标签、workspace card、message card、composer 主按钮和 Trace 终态显示 running、completed、failed、canceled 等状态时保持一致;Trace 阅读视图按 detail/history 事件顺序渲染可读 row,正确处理分页、终态、失败、自动展开和终态折叠;深链进入 session 与普通点击 session 走同一 authority path,删除或归档 session 后 deep link 不得复活 archived active tab。
浏览器回归验证至少覆盖以下用户可见路径:切换 session 后主工作区显示 loading 并恢复目标 sessionfresh browser context 深链进入 session 后以同一 message、turn 和 trace 标识还原 timeline;SSE 事件重复、乱序、丢失或重连后通过 SSE replay 或Kafka retention replay SSE 收敛,不触发旧 trace/session/turn 多端点补洞;session 标签、workspace card、message card、composer 主按钮和 Trace 终态显示 running、completed、failed、canceled 等状态时保持一致;Trace 阅读视图按 detail/history 事件顺序渲染可读 row,正确处理分页、终态、失败、自动展开和终态折叠;深链进入 session 与普通点击 session 走同一 authority path,删除或归档 session 后 deep link 不得复活 archived active tab。
黄金链路回归必须覆盖完整用户流程:新建 session、发送 `hi`、running 可见、final response 可见、Trace terminal 可见、刷新、切换 session、回到原 session、删除或归档。长程链路回归必须使用真实采集脱敏长 Trace fixture,覆盖 detail 分页、SSE gap、sync replay、projection lag、terminal sealed、diagnostic 分仓和截图 artifact。两类回归都必须记录 fixture schema/redaction 版本、capturedFrom、capturedAt、derivedFrom、截图 SHA 或等价 artifact 校验值。
黄金链路回归必须覆盖完整用户流程:新建 session、发送 `hi`、running 可见、final response 可见、Trace terminal 可见、刷新、切换 session、回到原 session、删除或归档。长程链路回归必须使用真实采集脱敏长 Trace fixture,覆盖 detail 分页、SSE gap、Kafka replay、projection lag、terminal sealed、diagnostic 分仓和截图 artifact。两类回归都必须记录 fixture schema/redaction 版本、capturedFrom、capturedAt、derivedFrom、截图 SHA 或等价 artifact 校验值。
状态投影回归必须覆盖新建 session 后读侧失败的负向用例:用户显式 create mutation 成功并进入新 session 后,即使随后的 session detail、messages、list refresh、SSE、sync replay 或 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 修正页面后判通过。
状态投影回归必须覆盖新建 session 后读侧失败的负向用例:用户显式 create mutation 成功并进入新 session 后,即使随后的 session detail、messages、list refresh、SSE、Kafka replay 或 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 中主 authority 已返回 completed final response,随后 turn snapshot、trace detail page、SSE、sync replay 或 realtime diagnostic 失败。主 timeline 的 sealed final response 不变,诊断只显示在详情/感叹号/transport health 区域;Trace detail 延迟返回或分页缺口不得 remount 主消息卡片,也不得重置用户展开/折叠控制。
状态投影回归还必须覆盖 completed assistant 已 sealed 后的读侧失败负向用例:fixture 中主 authority 已返回 completed final response,随后 turn snapshot、trace detail page、SSE、Kafka replay 或 realtime diagnostic 失败。主 timeline 的 sealed final response 不变,诊断只显示在详情/感叹号/transport health 区域;Trace detail 延迟返回或分页缺口不得 remount 主消息卡片,也不得重置用户展开/折叠控制。
错误诊断回归必须覆盖 HTTP 400、401、403、404、409、500、proxy timeout、network error、Workbench projection blocker 和 sealed final 后 transport error。fake-server fixture 应按正式 `HwlabErrorEnvelope` 或等价结构重放 `error.diagnostic.traceId`、requestId、route、code 和 `valuesRedacted=true`,并用用户可见 DOM 断言诊断块、复制入口和可选 Trace Explorer 链接;测试不得通过内部 store、localStorage 或测试专用后门读取诊断字段。
@@ -529,11 +529,11 @@ Workbench 模块不得为了项目管理联动新增 iframe、嵌套 Workbench
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| CLIENT-WB-REQ-014 | Workbench调试台 | PJ2026-01040114 Workbench调试台 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md) |
| CLIENT-WB-REQ-014 | Workbench调试台 | PJ2026-01040114 Workbench调试台 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md) |
Cloud Web 应提供独立 Workbench 实时调试台,用于单步验证高纯度 SSE、统一 sync replay、detail-only 隔离和状态投影收敛。推荐入口是根侧边栏中的独立导航项和独立路由,例如 `/workbench/debug`,而不是继续扩展现有 Workbench topbar 诊断弹窗。原因是单步调试需要深链、fixture 选择、事件播放控制、请求 ledger、cross-page 对照和 Playwright 直达,长期嵌在真实 Workbench 会污染用户任务流和真实 store。
Cloud Web 应提供独立 Workbench 实时调试台,用于单步验证高纯度 SSE、Kafka retention replay、detail-only 隔离和状态投影收敛。推荐入口是根侧边栏中的独立导航项和独立路由,例如 `/workbench/debug`,而不是继续扩展现有 Workbench topbar 诊断弹窗。原因是单步调试需要深链、fixture 选择、事件播放控制、请求 ledger、cross-page 对照和 Playwright 直达,长期嵌在真实 Workbench 会污染用户任务流和真实 store。
调试台必须默认使用隔离 store/reducer harness。纯 SSE 模式下,页面只消费 fake typed event 数组或 fake EventSource adapter;任何自动 `/v1/workbench/sync``/v1/workbench/turns/:id``/v1/workbench/sessions/:id/messages``/v1/workbench/traces/:id/events` 或旧 `/v1/agent/*` 请求都必须进入 request ledger 红灯。显式打开 sync replay 模式时,也只能使用 `/v1/workbench/sync` 等价 fixture,不得恢复 trace/session/turn 多端点补洞。
调试台必须默认使用隔离 store/reducer harness。纯 SSE 与 Kafka replay 模式只消费 fake typed event 数组或 fake EventSource adapter;任何自动 `/v1/workbench/sync``/v1/workbench/turns/:id``/v1/workbench/sessions/:id/messages``/v1/workbench/traces/:id/events` 或旧 `/v1/agent/*` 请求都必须进入 request ledger 红灯。
调试台至少应提供这些子标签页:纯 SSE 单步、Authority Gate、Terminal Seal、Reconnect/Cursor、Cross Page、Detail Only、Snapshot Merge、Fake Provider 和 Request Ledger。每个子标签页应输出 event header、authority decision、state diff、DOM-like projection、expected verdict 和可复制的 bounded 证据。Fake Provider 页可使用 fake-echo/fake model provider 的脱敏 fixture 或合成事件序列,但不得依赖真实 provider 成败作为通过条件。
@@ -1,4 +1,4 @@
# PJ2026-0104010803 Workbench唯一投影
# PJ2026-0104010803 Workbench唯一投影(已废弃)
## 修改历史
@@ -7,12 +7,8 @@
当前正文仍在规格治理草稿中;未定稿前不新增版本号,不为单次编辑追加 `待提交` 版本。
> 裁决优先级:本规格中以 PostgreSQL aggregate event stream、transactional projector、durable outbox 或 `/v1/workbench/sync` 作为实时/回放 authority 的条款,已被 2026-07-14 的 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) `draft-2026-07-14-p0-pure-kafka-authority` 取代。当前权威链固定为 `agentrun.event.v1 -> mapper -> hwlab.event.v1 -> 实时 SSE / Kafka retention 回放 SSE`PostgreSQL 只可作为非阻塞派生读模型,不能成为 Cloud API 启动、Kafka 实时或回放的前置。未完成正文重整前,冲突条款一律以最新专项裁决为准。
## 正文
## PJ2026-0104010803 Workbench唯一投影需求规格
## 1. 文档控制
| 字段 | 内容 |
@@ -20,630 +16,36 @@
| 编号 | PJ2026-0104010803 |
| 短名 | 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-24-p0-aggregate-event-stream; draft-2026-06-24-p1-opencode-message-part-authority; draft-2026-06-25-p0-serve-session-aggregate-authority; draft-2026-06-25-p0-session-warm-runner-contract; draft-2026-06-27-p0-read-model-timeline-contract; draft-2026-06-28-p0-d518-session-timeline-consistency |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 状态 | 已废弃 |
| 替代规格 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.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) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版:正文只保留 Workbench 唯一投影的稳定使命、范围、术语、系统边界、内部分工和原子需求。
## 2. 废弃裁决
## 2. 目的和范围
本规格曾把 PostgreSQL aggregate event stream、transactional projector、durable projection outbox 和数据库 replay 定义为 Workbench 的唯一提交序与实时前置。该架构已废弃,不再是实现、测试、发布门禁或源码引用的有效依据。
### 2.1 目的
Workbench唯一投影负责把 AgentRun 执行事实收敛成 HWLAB 自有的 durable Workbench facts,使 Web、CLI、REST、SSE、fake-server 和浏览器回归都消费同一份可恢复、可分页、可诊断的用户态会话事实。
本专项的目标状态是:AgentRun run、command、event 和 result 只作为执行事实输入;HWLAB 只有 `WorkbenchProjectionWriter``WorkbenchProjectionFinalizer` 写入 Workbench factscloud-api boot/background scheduler 是 startup/resume 的 authority,负责扫描 durable open checkpoint 和 running/projecting turn 并恢复追平;投影推进只能由上游 source event/result、projection writer/finalizer、background scheduler/reconciler 或显式受控 checkpoint replay/reprojection 触发。所有 `GET /v1/workbench/*` 和兼容读路径都只通过 `WorkbenchReadModel` 读取,不在读取时调用 AgentRun、Code Agent manager、trace polling、result polling、`hydrateRealtimeGap` 或 workspace repair 推进事实。Workbench 必须满足 0repair:页面、GET、SSE、fake-server 和 web-probe 都不得通过 reload、切换 session、`sessionRepair``realignFreshSession`、localStorage truth、SSE gap repair、visibility gap refresh 或 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 和浏览器本地状态重新排序。
Workbench message/part authority 必须采用类似 OpenCode serve 的职责分离:prompt admission、session status、message page、message part、event stream 和 abort/cancel 分别有清晰 authority,最终由同一投影提交序收敛。用户消息、assistant 文本、tool/command 行、diagnostic、steer/cancel 控制事件和 final response 必须是稳定 `messageId/partId/order/status/sealedAt` 的 part 事实;禁止把同一 trace 的全部 assistant 输出压成单个 trace-level assistant message,再由 read model、前端 store、CLI renderer 或 analyzer 根据文本内容重新选择“最终回答”。
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 detail、SSE gap、realtime timeout、transport close、read model lag 或 compat wrapper 失败只能写入 trace detail、transport diagnostic、projection diagnostic 或 session health,不能覆盖 sealed 主正文。
CLI trace 视图是 web-probe 工测和自动判别器的人工可读基准。`web-probe collect/observe` 只负责按固定频率保存采样事实;`analyze turn-summary``analyze trace-frame` 从既有采样事实或同源 read model 渲染文字版 trace 截图,不新增第二套保存来源。自动判别器的 finding 必须能被 CLI trace 视图复核;当二者冲突时,以 CLI trace 视图暴露的有序 turn/message/part/final response 事实作为需要修复的可见症状。
D601 v0.3 可以在 `hwlab-v03` namespace 内为 `hwlab-workbench-runtime` 使用 Redis 派生读缓存,但该缓存只能保存 WorkbenchReadModel 从 durable facts 组装出的短 TTL 快照。Redis 不写入 Workbench facts,不推进 checkpoint,不生成 lifecycle、terminal、final response 或 projectionStatus;缓存 miss、stale 或 unavailable 只能改变读路径性能诊断,不能改变唯一投影事实。
### 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` 的组件边界。
- 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 输出要求。
- WorkbenchReadModel 内部的 Redis 派生读缓存 key、payload、失效、TTL 和降级边界。
- Web reducer、CLI renderer、web-probe analyze/collect、fake-server fixture 和 Playwright 回归对同一 durable projection 的消费规则。
- 本专项范围内新增或重构源码文件的 SPEC 头部引用规则。
- D518 HWLAB v0.3 Workbench fake-echo 与 dsflash-go 原入口哨兵对 timeline、refresh、session switch、timing 与 OTel 可见性的关闭验收合同。
### 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)。
- Redis 部署、镜像、资源、NetworkPolicy、TTL 数值和指标接入归 [PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) 与 YAML-first 运维;本专项只定义其不能改变唯一投影 authority。
## 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 到达、后台恢复或显式 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 的唯一提交序。 |
| message/part authority | Workbench timeline 的消息和片段权威。每个 user/assistant/tool/diagnostic/final response 片段都有稳定 `messageId``partId``order``status` 和 sealed 状态;trace-level 文本、DOM 行、result envelope 或 analyzer 不能替代它选择最终内容。 |
| WorkbenchReadModel | 唯一读取 Workbench facts 并组装 session rail、session detail、message page、turn snapshot、trace event page 和 projection diagnostics 的读模型。 |
| 上游投影推进 | Workbench facts 只能由 projection writer/finalizer、background scheduler/reconciler、AgentRun source event/result outbox 或显式受控 checkpoint replay/reprojection 推进;REST GET、Web 页面、SSE consumer、SSE open/error/visibility handler、web-probe、fake-server 和 CLI renderer 只能观察或展示投影与诊断,不能以 gap hydration、trace/result polling、reload 或 read-through sync 触发写侧投影。 |
| 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 重启或后台任务丢失后继续追平。 |
| projection state | checkpoint 的运行态扩展,至少记录 traceId/sessionId/sourceRunId/sourceCommandId、lastSourceSeq、lastProjectedSeq、sourceLatestSeq、projectionStatus、projectionHealth、resultSyncState、lastError/blocker、failureCount 和 nextRetryAt。 |
| result sync state | AgentRun `/result` 归档或终态补全的低优先级状态;它不得阻塞运行中 events projection。 |
| sourceLatestSeq | finalizer 在本次或最近一次拉取中观察到的 AgentRun command 最新 sourceSeq,用于诊断投影 lag;它不得替代 lastSourceSeq 成为已提交事实。 |
| projection diagnostic | 暴露 projection lag、blocker、lastProjectedSeq、sourceRunId、sourceCommandId、updatedAt 和恢复状态的可诊断字段。 |
| terminal outbox | AgentRun runner 在 command 结束时写出的 durable terminal envelope,包含 runId、commandId、terminalStatus、failureKind、final response 或 terminal error 等终态输入;它必须被 Workbench finalizer 幂等消费。 |
| already terminal cancel | 用户发起 cancel 前,HWLAB 发现 AgentRun command 或本地 sealed projection 已经 terminal 的状态;此时 cancel mutation 不得覆盖 terminal facts,应返回 already-terminal/no-op 或触发 terminal projection。 |
| control command boundary | prompt、steer、retry 和 cancel 的受控 mutation 边界。每个控制命令必须有独立 action、target turn/run/command、HTTP route、commandId 或 no-op reason;采集器、analyzer 和 Web 不能把后续 steer/cancel 误归入前一个 prompt 提交。 |
| AgentRun execution diagnostic | AgentRun durable ledger 对 runner job observation、stale lease、terminalReportState、reconciler backlog 和不可恢复 blocker 的诊断输出;Workbench 只能把它作为 projection diagnostic 输入,不拥有执行状态写权。 |
| transport diagnostic | SSE、旧 turn polling、trace detail、result sync、realtime timeout 或浏览器网络层观察到的可见性诊断;它只能描述传输或读侧健康,不拥有 message text、finalResponse 或 terminal status 写权。 |
| projection health | 对 projection diagnostic 的只读解释,状态至少区分 `projecting``caught-up``degraded``stalled`;它不推进 facts,也不得把 stale projecting 标为 caught-up。 |
| timing display input | Workbench ReadModel 输出的 `startedAt``lastEventAt``finishedAt` 和 sealed `durationMs` 等投影时间字段;它们是浏览器相对时间文案的唯一事实输入。浏览器本地 now 只能参与直接渲染计算,不成为 Workbench facts,也不得通过 UI 侧平滑、滤波、单调 floor、跳变 cap、二次缓存或本地推断伪造更连续的 `elapsed/recent` 事实。 |
| TraceEventPage | 由 WorkbenchReadModel 返回的 trace 分页事实,必须按 `projectedSeq` 单调排序,并保持 `range.fromSeq <= range.toSeq`;空页用显式 empty range 表达,不生成非法区间。 |
| 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 推进事实;本专项禁止该模式。 |
| 读侧推理 | REST GET、SSE consumer、compat wrapper、CLI renderer、Web reducer/selectors、Trace renderer、fake-server 或测试断言根据 trace tail、message text、tool event、result cache、session summary、list row、workspace snapshot、localStorage 或 elapsed timeout 推断 turn/session/message lifecycle、terminal、running 或 final response 的行为;本专项禁止该模式。 |
| 事后 repair | 页面或测试发现 active route/session/message/trace 已经分裂后,再通过 reload、切换 session、`sessionRepair``realignFreshSession`、workspace selection repair、active tab repair、localStorage truth、GET read-through 或 SSE gap repair 把 UI 补成看起来正确;本专项禁止该模式。 |
| Redis派生读缓存 | WorkbenchReadModel 内部可选的 Redis 缓存层,只保存从 durable Workbench facts 组装出的 session summary、terminal turn snapshot 或 terminal trace page 快照;它可丢弃、可过期、可重建,不是 Workbench facts、checkpoint 或 lifecycle authority。 |
| cache authority input | 构成缓存 key 与有效性判断的权威输入,至少包含 schema version、actor visibility input、session/turn/trace/cursor、projection revision/seq 或等价字段;这些输入必须来自 durable facts/read model。 |
| cache diagnostic | `cacheStatus``cacheAgeMs`、cache key class、projection revision/seq、dbQueryAvoided 和 Redis unavailable/stale 等读路径诊断;它只能解释性能和新鲜度,不拥有主 timeline 写权。 |
| CLI trace 视图 | `web-probe analyze` 从采样事实渲染的文字版 trace 视图,包含多 turn 的 `turn-summary` 和单 turn/单 frame 的 `trace-frame` 两层;它用于人工复核自动 finding,不保存新事实,不从 DOM 重新推断。 |
| canonical timeline digest | ReadModel、OTel 和 web-probe 用于比较同一 session/timeline 快照是否一致的脱敏摘要。摘要至少覆盖 sessionId、messageId、role、turnId、traceId、message/part order、status、sealed/timing 字段和文本哈希,不包含完整 prompt、完整 final response、Secret、cookie、Authorization 或 provider payload。 |
| Serve Session Aggregate Authority | Workbench 会话级聚合根,统一接收 prompt admission、steer、cancel、retry、run-state、message/part、trace/timing 和 terminal/final response 的写入序列;它是 Web、REST、SSE、CLI 和 web-probe 可见状态的上游 authority。 |
| durable input/command fact | 用户输入或控制命令进入执行前写入的持久事实,至少绑定 `sessionId``turnId``messageId``commandId`、action、target、admittedSeq、status 和 no-op/blocker;它先于 AgentRun dispatch 或 Kubernetes job 创建。 |
| session execution lane | 同一 Workbench session 的受控执行 lane,把连续 prompt、steer、cancel 和 retry 串到同一 AgentRun session/run command channel、warm runner lease 或等价机制;它不能只是 metadata。 |
| warm runner contract | AgentRun/HWLAB 对连续 turn 的低延迟执行合同:已创建的 runner 在同一 session/run lane 内继续 poll 后续 command,或由明确 runner lease/session channel 承接后续 command;每 turn 新建独立 run-scoped runner Job 不能标称为 runner reuse。 |
## 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、显式 checkpoint replay/reprojection 请求、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、sealed final response、projection/transport 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 驱动追平、重启恢复和显式 checkpoint replay/reprojection 的同一幂等入口 | 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,分仓保存 sealed message projection、trace detail、session status 和 transport diagnostics | 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 引用和实现版本追溯 | 规格治理 | 后续实现审计 |
| 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 |
| PJ2026-010401080311 | CliTraceView | 本规格 6.11 | web-probe 采样事实的 turn-summary/trace-frame 渲染、final response 展示和 analyzer 判据 | ReadModel、AggregateEventStream | 工测复核、自动 finding、issue 证据 |
| PJ2026-010401080312 | ServeSessionAggregate | 本规格 6.12 | prompt admission、steer/cancel、run-state、message/part、trace/timing 的 session aggregate authority | API契约、Agent编排、HWLAB接入 | Web、CLI、web-probe、fake-server |
### 5.1 OpenCode serve 对照原则
本专项采用 OpenCode serve 的架构边界作为对照,但不复制其实现。`/root/opencode/packages/server/src/groups/session.ts` 将 prompt admission 与等待/上下文读取分离;`groups/message.ts``handlers/message.ts` 通过 message page、cursor 和稳定顺序提供投影读取;`groups/event.ts``event-v2-bridge.ts``bus/global.ts` 把 location-scoped event 与单调 event id 作为同步基础;`session/status.ts``session/run-state.ts` 集中表达 idle/busy/retry/cancel`session/message-v2.ts``session/processor.ts` 以 message/part 追加、delta 和 cleanup 形成最终 assistant messageinstance HTTP API 将 prompt、async prompt 和 abort 作为不同 route。
HWLAB 的实现必须吸收这些边界:admission 只创建 stable turn/message/part/control idsstatus/cancel 不由 trace tail 推断;message page 和 trace page 只读 read modelevent stream/outbox 负责 replay 和 orderingassistant 最终内容来自 sealed assistant part,而不是从 trace 行、result envelope、DOM、`message.text` 或 analyzer fallback 重新挑选。凡是需要保留旧 compat route 的地方,都只能包装正式 mutation 或 WorkbenchReadModel,不能保留第二套 prompt/result/trace 仲裁。
### 5.2 目标架构图
```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]
CACHE[(Redis derived read cache)]
SSE[SSE publisher]
COMP[Compat wrappers]
AD --> WR
FIN --> WR
WR --> FS
FS --> RM
RM <--> CACHE
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。
目标架构还要求投影推进只发生在上游写侧。SSE publisher/handler 只发布和 replay durable outbox commitWeb/CLI/fake-server/SSE consumer 只消费 REST/SSE projection。SSE open/error、visibility change、route hydrate、Trace detail hydration、web-probe 观察、GET refresh 和 observer reload 不能触发 `hydrateRealtimeGap`、read-through sync、result sync 或 trace polling 来推动 projection;缺口只能表现为 projection diagnostic/blocker,并由 scheduler/reconciler/finalizer 或 source event/outbox 追平。
目标架构还要求彻底禁止读侧推理。`turn.status``message.status``session.running``trace terminal``finalResponse``projectionStatus` 必须是 projection writer/finalizer 已经写入 durable facts 的字段;read model、REST route、SSE consumer、compat wrapper、Web reducer、CLI renderer、fake-server 和测试只能读取和重放这些字段。AgentRun facts、trace events、message parts、result envelope、session summary、list row 和 workspace snapshot 只能作为 writer/finalizer 输入或诊断字段,不得在读取链路中通过优先级、fallback、最后事件、空文本、超时或 UI heuristic 生成生命周期事实。
### 5.3 目标数据流图
```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]
RM --> CACHE{derived cache?}
CACHE -->|hit| SNAP[REST snapshot / pages]
CACHE -->|miss/stale| FACTS
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.4 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.5 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 / running-projecting turns
Store-->>Boot: sourceRunId/sourceCommandId/lastSourceSeq/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 重启或慢任务超过短轮询预算后,boot/background scheduler 必须能从 durable checkpoint 和 running/projecting turn 找回需要追平的 sourceRun/sourceCommand,并以同一 writer 逻辑提交或记录 blocker。GET、SSE、Web 页面、visibility handler、fake-server、web-probe 和 CLI renderer 只能观察恢复状态,不能触发恢复、gap hydration 或 read-through sync。
### 5.6 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`, `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。`workbench_aggregate_event` 是 projector 和 replay 的提交输入,不允许 Web/API/CLI 直接把事件 payload 拼成另一套 timeline。
Assistant 输出必须按 message/part authority 建模。一个 turn 内可以有多个 assistant text/tool/diagnostic/final response part,每个 part 有稳定 order 和 statusfinal response 是 terminal commit sealed 的 final part,不是“最后一个非空文本”。同一 trace 只生成 `msg_<trace>_agent` 这类单一 assistant 容器而缺少 part 身份、order 和 sealed 状态的实现,不能作为本规格的完成形态。
运行中和终态 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.7 durable projection outbox 与 reconciler
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: aggregate events + facts + outbox + checkpoint)]
TX --> AEV[aggregate event stream]
TX --> FACTS[durable facts]
TX --> OUTBOX[durable outbox rows]
TX --> CP[checkpoint]
OUTBOX --> SSE[SSE cursor replay]
OUTBOX --> REC[reconciler worker]
FACTS --> RM[ReadModel]
RM --> REST[GET /v1/workbench/*]
SSE --> STREAM[SSE events]
CP --> BOOT[boot/resume scheduler]
BOOT --> FIN[Finalizer]
FIN --> WR
```
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 tailcloud-api 重启后不需要内存 listener 即可恢复 SSE 输出。
Reconciler 是后台 worker,消费 outbox 和 checkpoint 驱动 finalizer 追平。它取代旧的请求/轮询式 `syncAgentRunChatResult` 推进模式:AgentRun result sync 只负责拉取/写入 projection source state,事件推进由 outbox/reconciler 管道统一处理。
### 5.8 SSE cursor replay 架构
```mermaid
sequenceDiagram
participant Client as Web/CLI
participant SSE as SSE handler
participant DB as durable outbox
participant WR as ProjectionWriter
Client->>SSE: GET /v1/workbench/events?afterSeq=N
SSE->>DB: SELECT outbox WHERE outboxSeq > N
DB-->>SSE: replay rows (terminal, events, diagnostics)
SSE-->>Client: replay events
Note over WR,DB: new projection commit
WR->>DB: INSERT outbox row
DB-->>SSE: live tail notification
SSE-->>Client: live event
```
SSE handler 不再直接订阅内存 `traceStore.subscribe`。它只从 durable outbox 读取:连接建立时执行 replay(按 `afterSeq` 查询历史 commit notification),replay 完成后切换到 live tailpoll 或 LISTEN/NOTIFY 等价机制)。cloud-api 滚动、多副本和多用户同看同 trace 时,SSE 从同一 durable outbox 恢复,不丢 terminal/sealed 状态。
### 5.9 DB 唯一约束与幂等保障
`workbench_trace_events` 表必须有 `(trace_id, source_event_id)` 唯一约束,防止并发或历史数据写入重复 source event。allocator 查询 sourceEventId 复用 projectedSeq 时,数据库层必须硬约束阻断重复写入。
`(trace_id, projected_seq)` 也应有唯一约束,确保同一 trace 内 projectedSeq 单调不重复。历史 collision 数据在 migration 时通过 collision blocker 策略处理:检测到重复时暴露 `projectionStatus=blocked``projectionHealth=degraded` 和稳定 blocker code,不把损坏序列交给 renderer 继续展示。
Projection outbox 的 `outboxSeq` 必须全局单调递增,可通过数据库 sequence 或等价机制生成。outbox 行与 projection facts 在同一事务提交,保证 commit notification 与 durable facts 一致。
Aggregate event stream 必须同时具备 `(eventSeq)` 全局单调约束、`(aggregateId, aggregateSeq)` aggregate 内单调唯一约束和来源幂等唯一约束。来源幂等键至少覆盖 `sourceRunId``sourceCommandId``sourceEventId` 或等价 source result idadmission、cancel 和 replay/reprojection 这类本地事件必须有稳定 deterministic eventId。任何需要重排、补 terminal 或修 timing 的逻辑都必须追加受控事件并重新投影,不得直接改 read model 或前端 store。
### 5.10 0读侧推理验收矩阵
| 层 | 禁止模式 | 验收方式 |
| --- | --- | --- |
| 后端 turn projection | `result?.status ?? trace?.status ?? session?.status` | 源码扫描 + 单元测试构造多来源矛盾样本 |
| 后端 SSE handler | `traceStore.subscribe` / 内存 trace snapshot | 源码扫描 + cloud-api 重启后 SSE cursor 恢复验证 |
| 后端 trace snapshot | `events.at(-1)` 推导 status/lastEvent | 源码扫描 + 矛盾 events 样本测试 |
| 后端 compact result | result/traceSummary/agentRun/memoryTrace 混合 | 源码扫描 + GET 路径不访问旧 compact path 验证 |
| 后端 message projection | trace-level assistant id 或 firstNonEmpty/fallback 选择 final response | 源码扫描 + 多 assistant part / running final 空值样本 |
| 前端 store | `events.at(-1)` 推导 activity/label/status | 源码扫描 + fake-server Playwright |
| 前端 subscription | turn poll + trace poll + event tail 合并 lifecycle | 源码扫描 + SSE gap/timeout Playwright |
| 前端 timing | `lastEventAgeMs` 作为相对时间权威 | 源码扫描 + fake clock Playwright |
| CLI renderer | `lastEvent.status` 推 trace lifecycle 或 DOM 行顺序选择 final response | 源码扫描 + CLI 同源语义验证 |
每层验收必须先用负向 fixture 形成红灯,再用修复后代码证明通过。负向源码扫描是辅助证据,不能替代 fake-server Playwright 与 D601 v0.3 web-probe。
## 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/sealedAt/createdAt/updatedAt | timeline message 事实;assistant final text 通过 part 表达,sealedAt 或等价字段表示主消息结果已封存。 |
| part | partId/messageId/type/status/text/tool/error/finalResponse/sealedAt/traceRef/order | 文本、工具、错误、final response 和 trace 摘要的可组合展示事实;final response part sealed 后不得被读侧 diagnostic 覆盖。 |
| turn | turnId/sessionId/traceId/status/terminal/sealedAt/failureKind/sourceRunId/sourceCommandId/messageIds/startedAt/lastEventAt/finishedAt/durationMs | 一次用户提交、steer、retry 或 cancel 的生命周期事实;运行中相对时间显示只消费这些投影时间戳。 |
| trace event | traceId/projectedSeq/sourceSeq/sourceEventId/type/status/timestamp/redactedPayload | Workbench trace page 的分页事实;projectedSeq 是唯一 cursor。 |
| checkpoint | turnId/traceId/sourceRunId/sourceCommandId/lastSourceSeq/lastProjectedSeq/sourceLatestSeq/status/attempt/lastAttemptAt/lastError/blocker/updatedAt | finalizer 追平位置、幂等边界、恢复状态和退避诊断。 |
| diagnostic | sessionId/turnId/traceId/projectionStatus/health/lag/blocker/sourceRunId/sourceCommandId/lastSourceSeq/lastProjectedSeq/sourceLatestSeq/updatedAt | GET 和运维可见的 projection 状态,不推进事实。 |
Checkpoint/projection state 唯一键必须包含 `sourceRunId``sourceCommandId` 和对应 `turnId`/`traceId`,或等价的 command-scoped 唯一键。同一 AgentRun run 的不同 command 不得共享 cursor;旧 command 的历史事件不得误投到新 turn。`lastSourceSeq` 表示已经成功投影的来源位置,`sourceLatestSeq` 只表示最近观察到的来源最新位置;二者差值可用于 lag/health 诊断,但不得让读侧推断 terminal。
AgentRun events 进入 Workbench trace facts 时,FactsStore 必须把 filtered trace event 写入和 projection cursor 推进放在同一 durable commit 中,或采用等价的幂等事务语义。cursor 只能在对应 source event 已成功持久化或被确认幂等去重后推进;不得先更新 `lastSourceSeq` 再异步 best-effort 写 trace event。cloud-api 重启后必须直接从 projection state 的 `lastSourceSeq` 继续请求上游 events,不能通过扫描 `agent_trace_events`、trace tail、session JSON、result payload 或长 trace 全量重放来反推出下一次 `afterSeq`
Facts store 必须支持幂等 upsert、terminal commit、projection checkpoint、diagnostic update、open checkpoint 扫描、running/projecting turn 扫描和按 owner visibility 过滤的分页查询。`agent_sessions.session_json` 可作为迁移期 metadata 来源,但不得继续承载业务 projection 真相。
Facts store 必须把 assistant 文本、tool/command 行、diagnostic 和 final response 持久化为 message/part facts。对同一 turn/trace 的 assistant 输出,必须能按 part order 恢复 running 中间态、steer 后续输出和 terminal final part;不得只持久化 trace-level assistant message id,再让读取端从 `text/content/message/finalResponse` 的 first-non-empty/fallback 链条重建主消息。
### 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、重启恢复或 checkpoint replay/reprojection 不得创建重复 assistant message、重复 terminal event 或冲突 session summary。
Writer 必须在 admission 阶段为 user message、assistant message 和初始 part 分配稳定身份,并在后续 event/result/steer/cancel projection 中追加或封存对应 part。assistant 文本增量、工具输出、backend diagnostic、steer 确认、cancel 结果和 final response 不得写入同一个无 order 的文本字段;terminal final response 必须是明确 partKind/status/sealedAt 的 sealed part。
Writer 的 terminal commit 必须同时写入 assistant final text、finalResponse part、message/turn terminal status、trace terminal fact、session running=false、checkpoint 和 `sealedAt` 或等价 sealed 标记。Completed、failed、canceled、blocked 都是 terminal result;若 AgentRun 或 projection 给出可读 final error/blocker,它必须作为 sealed final response 的一种结果写入,而不是作为后续 transport diagnostic 写入主正文。
### 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 后、后台恢复和显式 checkpoint replay/reprojection 可以触发 finalizer,但这些入口必须调用同一幂等 finalization 逻辑。显式 replay/reprojection 是受控投影恢复入口,不是前端、GET、SSE 或 probe 的事后 repair;它不得改变 active session、route、当前消息区或用户显式选择。
Finalizer 不得伪造 terminal、不取消 AgentRun、不用日志尾部推断 completed,也不得让 GET route 临时同步执行 finalization。若 AgentRun 事实暂不可取或映射失败,finalizer 应写入 diagnostic blocker,保留 retry 所需 sourceRun/sourceCommand/checkpoint。
AgentRun rolling recovery 的缺口必须显式落入 projection diagnostic。若 AgentRun durable ledger 缺 terminal fact、runnerJob observation 尚未恢复、lease stale 但 Kubernetes phase 未确认、terminalReportState 仍 pending/outbox-retrying,或 AgentRun result/diagnosis API 返回 unrecoverable blockerFinalizer 应把这些上游事实归一化为 Workbench projectionStatus、projectionHealth、blocker、sourceRunId、sourceCommandId 和 nextRetryAt 等诊断字段。Finalizer 不得根据 Kubernetes Job completed、stdout tail、最后一个 AgentRun event、elapsed timeout、session summary 或 Web 当前页面状态补造 Workbench completed。
Startup/resume authority 只属于 cloud-api boot/background scheduler。该 scheduler 启动后必须扫描 durable open checkpoint、`projectionStatus=projecting` 或等价 running/projecting turn,按 bounded concurrency、attempt、lastAttemptAt 和 backoff 推进;它只能调用同一 `WorkbenchProjectionFinalizer/Writer`,不得新增第二套 result polling、manager shortcut 或 GET repair。恢复任务失败时必须写入 `lastError/blocker` 和下一次 retry 所需 cursor,不能静默丢弃。
Finalizer 的 cursor 必须以 command 和 checkpoint 为边界追平。对同一 run 的第二个及后续 commandfinalizer 必须从该 command 自己的 checkpoint 或 command-scoped event/result window 继续,避免每次从 run head 扫描大量旧事件;当只能获得 run-level event page 时,也必须用 `sourceCommandId`、稳定幂等键和 source checkpoint 过滤旧 command 事件。result 先到、events 后到、terminal event 缺失但 command result terminal、source event 缺口或 sourceSeq 回退都必须进入 diagnostic/blocker 或补洞路径,不得在读侧修正。
运行中投影必须以 AgentRun events 增量接口为主读源:finalizer/resume loop 使用 durable `lastSourceSeq` 调用上游 `events?afterSeq=<lastSourceSeq>&limit=<boundedPage>`,再按 commandId 和 seq window 过滤并提交 Workbench facts。running loop 不得为了恢复或刷新进度同步等待 `/result`,也不得在每次拉取时从 run seq 0、长 trace、result envelope 或历史 events 数组重新扫描。发现 terminal evidence 后,finalizer 可以把 projection 标记为 terminal/pending-result,并把 `/result` 同步交给后台低优先级归档;`/result` timeout 只能更新 `resultSyncState``lastError/blocker` 和 retry/backoff,不得阻止 events cursor 继续推进。
Projection resume 对 `projectionStatus=projecting/degraded/stalled` 或等价 running turn 超过受控阈值的 trace,必须周期性读取 AgentRun command result authority,不能只等待 events page 中出现 terminal event。Command result 已 terminal 时,finalizer 必须写入同一 terminal commit;若 result 拉取失败或超时,`resultSyncState=timed_out/failed/pending` 必须进入 projection state 并按 backoff 重试。长期 `terminal=0 failed=0` 的 resume pass 不能被记录成无问题完成;它必须暴露候选数、result sync 状态和下一次 retry 信息。
Cancel 是受控 mutation,不是终态仲裁。`/v1/agent/chat/cancel` 或 Workbench cancel mutation 在转发 AgentRun cancel 前,必须先检查本地 sealed terminal projection,并在可能时读取当前 run/command result 或 command state。若上游 command 已 `completed``failed``blocked``canceled` 或等价 terminalcancel 不得把 Workbench turn 改写为 canceled;应返回 already-terminal/no-op 或触发 terminal projection,使 Workbench 保持真实 terminal final response。
Finalizer 对 sealed turn 的后续重试只能推进 trace detail completeness、result archive、diagnostic health 或受控 replay/reprojection;不得把 `/result` timeout、events gap、provider transport error、poll idle timeout 或 hydration failure 映射成新的 assistant 主正文、finalResponse、message status 或 turn terminal status。
### 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。
Read model 可以在组装完成后读取或写入 Redis 派生读缓存,但缓存 payload 必须等价于同一 durable facts/read model DTO 的可重建快照。缓存 key 必须包含 cache authority input;命中缓存不得绕过 owner visibility、不得补造缺失 facts、不得把 stale payload 升级成 terminal truth。Redis unavailable、timeout、decode failed 或 revision mismatch 必须退化为 cache diagnostic,并继续走 durable facts read 或明确 degraded。
`GET /v1/workbench/*` 必须纯读。若 projection 滞后,响应应输出 `projectionStatus``lastProjectedSeq``sourceRunId``sourceCommandId``blocker` 或等价 diagnostic 字段,不能在 GET 内做 read-through repair。
MessagePage 是 Workbench timeline 事实,不是 facts 表写入批次的直接 dump。WorkbenchReadModel 必须按 turn timeline、aggregate seq 或等价事件时间组装用户可见顺序;同一 turn 的 user message 必须位于对应 assistant/agent terminal message 之前,跨 turn 不得因为 user message 的 `projectedSeq/sourceSeq` 先整体写入、assistant terminal 后整体写入而输出 `UUAA``UUUAAA` 等 role cluster。`projectedSeq/sourceSeq/sourceEventId` 必须保留用于审计和幂等,但不得让 role/source bucket 或投影批次覆盖用户可见 timeline。
Session summary 的 title/preview 必须由 durable message/part projection 生成脱敏摘要,并随 session list/detail 作为显式字段返回。fallback `Session ses_*` 只表示 read model 缺摘要,是需要通过 OTel/session_list_read、web-probe finding 或 reprojection 暴露的问题,不是正常 UI 文案来源。
MessagePage、session detail 和 session list 必须输出足够的脱敏诊断来证明同一 session 的 canonical timeline 一致性。推荐字段为 `timelineDigest``roleSequencePrefix``adjacentSameRoleCount``traceIds``messageCount``projectionRevision` 或等价组合;这些字段可以作为 API DTO、OTel attribute 或 web-probe summary 出现,但必须同源于 ReadModel。刷新、session 切换、双观察者、deep link 与 SSE 重连后,同一 projection revision 的 digest 不得变化;若变化,系统必须把差异暴露为 projection/read-model/transport diagnostic,而不是在 Web reducer 或 analyzer 中重排掩盖。
Read model 严禁读侧推理。它不得从 `result?.status ?? trace?.status`、最后一条 trace event `status=completed`、message text 是否为空、part/tool row 状态、session list summary、workspace selected state、localStorage mirror、轮询耗时或 elapsed timeout 推断 turn terminal、message terminal、trace terminal、session running、final response 或 projection caught-up。若 durable facts 中唯一投影对象缺少这些字段,Read model 必须返回未知、投影中、degraded 或 blocker 等显式 diagnostic,由 projection writer/finalizer 修复源头;不得在读取时临时合成“看起来正确”的状态。
Read model 读取到 sealed final response 时,必须把主消息正文、finalResponse、message status 和 turn terminal 从 sealed projection 输出;projection diagnostic、trace detail diagnostic、transport diagnostic、result sync diagnostic 和 session health 只能作为独立字段或详情区数据输出。读取链路不得因为后续 turn snapshot 失败、trace detail page 失败、SSE gap、realtime timeout 或 compat wrapper 失败而替换 sealed 主正文。
Read model 输出 running turn 时,finalResponse 必须为空值或等价 `(空内容)` 展示输入;诊断、后台状态解释、steer accepted 文案或用户 prompt 不能填入 finalResponse。Read model 输出 terminal turn 时,finalResponse 只能来自 sealed final part;若 sealed final part 缺失,应输出 projection blocker,而不是回退到 user message、assistant 中间文本、trace 最后一行或 result summary。
Projection health 必须只解释 durable diagnostic。`projectionStatus=projecting``lastProjectedSeq < sourceLatestSeq`、checkpoint stale 超过受控阈值、存在 `lastError/blocker` 或 attempt 正在退避时,不得返回 `caught-up`;应返回 `projecting``degraded``stalled`,并暴露 `blocker``lastProjectedSeq``sourceRunId``sourceCommandId` 和更新时间。`caught-up` 只能表示对应 command checkpoint 已追平可见 source facts,或 source 明确仍 running 且无新可投影 facts。
Trace event page 必须按 `projectedSeq` 单调返回,响应范围必须合法。非空页满足 `range.fromSeq <= range.toSeq`;空页必须用明确空集合和空 range/null range 表达,禁止出现 `fromSeq=5/toSeq=4` 这类非法区间。`projectedSeq` 是 Workbench 读取 cursor`sourceSeq` 只作为来源审计字段;二者不得混用。
Trace event page 的可见性必须以 durable turn/message/session 关系和 owner visibility 判断,不能只依赖 session 当前 `lastTraceId`。同一 session 后续产生新 trace 后,旧 trace 只要对应 turn、message 或 projection facts 对当前 actor 可见,`GET /v1/workbench/traces/{traceId}/events` 仍应返回 200 和 trace page;若 trace facts 缺页或 projection 未追平,应返回 projection blocker/degraded,而不是 actor 不可见 404。真正 archived/deleted/not-found 的生命周期必须来自 canonical lifecycle projection。
Trace event page continuation 的空窗口不得升级成 404。若 page 没有新 event、但 trace checkpoint 或 projection diagnostic 显示 read model 尚未追到 `traceLastSeq/lastProjectedSeq`,响应应为 `200` 空页并标记 `projectionStatus/projectionHealth=projecting` 或等价 degraded/stalled,暴露 `latestProjectedSeq``lastProjectedSeq``traceLastSeq``fullTraceLoaded=false``diagnostic.code=workbench_trace_events_missing``fullTraceLoaded=true` 只能表示本次 page 实际 `toProjectedSeq` 已追到 `traceLastSeq` 且没有更多 page,不能仅由 `hasMore=false``range.total` 推断。
Trace event page 的 OTel/read-model 诊断必须能解释 web-probe 的 trace-row-order 与 completion/timing finding。每次读取至少应能关联 traceId、sessionId、range.fromProjectedSeq、range.toProjectedSeq、returnedEvents、totalEvents、hasMore、fullTraceLoaded、traceLastSeq、projectionStatus、projectionHealth、sourceRunId 和 sourceCommandId;这些字段应来自同一 ReadModel 响应或同源 OTel span,不能由 analyzer 在事后猜测。
Workbench facts/read model 的 PostgreSQL pool connect/query timeout 必须被转换为结构化 degraded/readiness/blocker 响应和日志,不能逃逸为 cloud-api 进程未捕获异常。Liveness 不应因单次 Workbench read query timeout 变为 EOFreadiness 或 route 响应应暴露 route、store method、timeout kind、runtime readiness、projection candidate count、相关 trace/run/command 摘要和 `valuesRedacted=true`
### 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。
Web server-state 必须分仓表达 `messageProjection``traceDetail``sessionStatus``transportDiagnostics`,或采用等价结构保证主消息投影与读侧诊断不会竞争同一字段。`messageProjection` 承载 role、status、text、finalResponse、turnId、traceId 和 sealedAt`traceDetail` 承载 events、pagination、hydration 状态和 trace diagnostics`sessionStatus` 承载 rail/card 运行摘要;`transportDiagnostics` 承载 SSE、poll、hydration timeout 或 realtime gap。Selectors 可以在消息详情入口汇总诊断,但主 timeline 的 sealed final response 不得被 diagnostic 文案替换。
active session 只能由 route sessionId 或用户显式选择产生。REST detail、session list、workspace summary、SSE event、trace page 或 turn snapshot 晚到时,只能更新其声明 sessionId 对应的 server-state bucket;不得重新选择 session、替换 URL、覆盖当前消息区、改变 composer 或把另一个 session 的 running/terminal 状态投射到当前页面。缺少 sessionId 或 session/trace 不匹配的 event 必须进入 authority mismatch diagnostic,不得猜测、fallback 或应用到当前 active session。
active turn/trace 只能来自 read model 声明的 current turn、用户显式选择或提交 mutation 返回的 stable ids。Web store 不得通过倒序扫描 messages、查找 running trace、`messageHasCompletedFinalResponse()`、最新 traceId 或 composer mode 推断 active trace;这类推断只能作为迁移期负向扫描对象。prompt、steer 和 cancel 的按钮 action 必须与当前 active command boundary 一致;没有 active turn 时,steer/cancel 应返回 no-op/blocker,不得 fallback 成普通 prompt。
SSE typed event 是 projection commit 的 live delivery 主路径,但事实来源仍是 durable aggregate event stream 和 Workbench read model。SSE 断线、丢事件或重连后,Web 只能通过同一 durable cursor 的 SSE replay 或统一 `/v1/workbench/sync` replay 追平;不得回退到 session/messages/turns/trace detail 多端点补洞。running trace 在 terminal 前 detail page `hasMore=false` 只表示当前 detail 页追平,不得设置永久 `fullTraceLoaded=true`,也不得影响主 turn terminal 判定。
Web reducer 必须提供 sealed guard:对已经有 `sealedAt` 或等价 sealed 标记的 assistant message/turn,旧 turn polling、trace detail、SSE gap、late realtime diagnostic、compat wrapper error 或 elapsed timeout 只能更新所属 trace/session 的 diagnostic bucket,不得写回 message text、finalResponse、message status 或 turn terminal。需要主动修改 sealed 主正文时,必须来自同一 durable projection 的新 revision、受控 replay/reprojection 或明确用户 mutation,而不是读侧失败。
运行中相对时间显示必须保持单一权威:Web server-state 只保存 WorkbenchReadModel 返回的 `startedAt``lastEventAt``finishedAt``durationMs` 和 sealed 标记;浏览器 ticker 只在组件渲染时计算 `now - startedAt``now - lastEventAt` 文案。`Date.now()`、页面本地 `updatedAt``lastEventAgeMs` 快照、轮询间隔和 trace detail 读取时间不得写入 reducer/store,也不得影响 lifecycle、terminal、session ordering 或 projection diagnostic。终态消息的耗时只使用 sealed projection 值,不能随浏览器 ticker 继续增长。
刷新和 session switch 恢复必须保持 active session bucket 不变量。Web 在重新 hydrate、切出再切回、双页面同时观察、SSE replay、`/v1/workbench/sync` replay 或 optimistic submit reconcile 时,只能用 ReadModel 声明的 sessionId/turnId/messageId/traceId 更新对应 bucketpending optimistic message 必须按 stable ids 与服务器 message 对账,不能按数组位置、最近 traceId、session rail 行或 DOM 到达顺序合并。web-probe 在第 1、5、10 轮刷新或切换后看到的主 timeline digest、role sequence、session rail title/preview 和 traceId 归属必须与同一 ReadModel 快照一致。
### 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 组合矛盾。
Durable recovery 红灯必须覆盖长 run、多 command 和大量旧事件场景。fixture 应优先从 D601 v0.3 真实样本脱敏派生,至少覆盖同一 run 中后续 command 已 completed、eventCount 大于 2000、Workbench 只投影早期 seq、GET 保持纯读、随后后台 resume 从 command-scoped checkpoint 追平并展示 final response 的路径。用例还必须断言 GET 没有调用 AgentRun 或 result polling。
后端回归还必须包含不依赖 Web、CLI、数据库外部服务或其他模块的最小单元测试,直接覆盖 AgentRun events 拉取计划和 projection cursor 推进逻辑。该测试必须构造长 trace 或大量旧 source events 的反例,并断言下一次 `afterSeq` 来自 durable projection state/checkpoint 而不是遍历历史 trace event;测试应通过受控计数器、throwing iterable 或等价方式证明 cursor 计算复杂度不随历史 trace/event 数量线性增长。任何恢复到从 trace tail、result payload 或 events 数组扫描最大 sourceSeq 的实现都应让该单元测试红灯。
回归还必须覆盖读侧推理清零。后端和前端测试应构造最后一条 trace event 为非终态 `completed`、message text 为空、result/trace/session summary 字段互相矛盾或投影暂时滞后的样本,断言 API 与 DOM 不从这些原始字段推断 terminal/final/running。收口证据应包含负向源码扫描,至少覆盖 `result?.status ?? trace?.status``trace.status` 终结 turn、last event `completed` 终结 turn、message/session/list 状态覆盖 turn、elapsed timeout 改写 terminal 和 no-final-response 占位 final text 等读侧推理路径。
fake-server Playwright 应使用目标 node/lane 的真实采集脱敏 fixture,覆盖 session 切换、刷新、SSE 断线重连、sync replay、trace detail 分页和 terminal final response。纯 SSE 单步 fixture 应能禁用所有补洞请求,只用 typed event 验证 terminal seal、late stale rejection、detail-only rejection 和 cross-page convergence。D601 v0.3 public origin web-probe 应验证不切 session、不刷新页面、fresh deep link 和多观察者场景都通过同一 read model 收敛。
fake-server Playwright 还必须覆盖 timing display 红灯:在固定 projection timestamp、禁止 SSE/API 后续更新、使用浏览器 fake clock 推进的条件下,running 消息头部的“最近”和“耗时”应随 fake clock 前进;completed/failed/canceled/blocked 等终态消息的 sealed 耗时不得随 fake clock 前进。该测试不得读取内部 store,也不得通过更新 fixture、重新请求 API 或触发 projection repair 判定通过。
AgentRun rolling recovery 回归必须覆盖上游 stale ledger 与不可恢复 blocker 样本:manager rolling 后 AgentRun diagnosis 仍处于 pending observation 时,Workbench list/detail/messages/turn/trace 应一致展示 projecting/degraded/stalled diagnosticterminal facts 后续提交后,同一 durable projection writer/finalizer 应自然推进 sealed final response。测试不得通过 GET read-through、Web reload、切换 session、result fallback 或 fake-server 后门把 pending 状态改成 completed。
Terminal outbox recovery 回归必须覆盖 events page 缺 terminal、command result 已 completed 且含 final response 的样本。测试应断言 projection resume 会强制读取 command result authority、写入 completed terminal commit,并让 session/detail/messages/turn/trace events 全部从 durable facts 看到同一 terminal;随后用户 cancel 应返回 already-terminal/no-op,不得把 completed 改成 canceled。历史 trace 可见性回归必须覆盖同一 session 后续新 trace 成为 `lastTraceId` 后,旧 trace events 仍以 turn/message 关系返回 200 或明确 projection blocker。
Read model degradation 回归必须覆盖 PostgreSQL pool connect/query timeoutWorkbench facts query 应返回结构化 503/degraded 或 readiness/blocker,并记录脱敏诊断;测试不得通过未捕获异常、进程退出、liveness EOF 或 GET read-through repair 判定通过。
Sealed final response 回归必须构造 completed assistant 主正文已经展示后,`/v1/workbench/turns/{traceId}``/v1/workbench/traces/{traceId}/events`、SSE 或 realtime diagnostic 发生 timeout/500/gap/close 的样本,断言主消息正文、finalResponse、message status 和 turn terminal 保持 sealed 不变,诊断只出现在 trace detail、transport diagnostic、session health 或消息详情入口。回归还必须覆盖 trace detail 延迟返回、分页缺口和用户手动展开/折叠状态,确保 late update 不 remount 主消息卡片、不重置用户控制状态。
多 turn / running steer 回归必须覆盖连续 prompt、运行中 steer、terminal 后再次 prompt 和 cancel no-op 的组合。用例应断言 `turn-summary` 的每个用户消息绑定正确 traceId/runId/commandId`trace-frame --turn N``trace-frame --trace-id <id>` 读取同一 turnrunning frame 的 `Final Response` 为空;terminal frame 的 final response 是 sealed assistant final part;后续 steer/cancel 不会让 analyzer 把普通 prompt 标成 `prompt-routed-to-steer`,也不会让 trace-frame 误选用户 prompt、backend diagnostic 或 steer accepted 中间文案作为最终回答。
0repair 验收必须先在 fake-server + Playwright 中形成红灯:fresh context 直达 session A、普通点击切到 session B、A 的 delayed detail/turn/trace/SSE 晚到、用户没有提交 B 的新消息时,B 的 URL、active tab、message card、composer 和 trace detail 不得出现 A 的 user/agent 文本、running 状态或 terminal trace。web-probe 必须连续截图观察提交前、running、中间态、terminal 和晚到事件;不得用 reload、切换 session、`sessionRepair``realignFreshSession`、localStorage 修改或 helper 自动点击修正页面后再判通过。
D518 HWLAB v0.3 的 issue #1217 closeout 必须在真实 public origin 上完成 fake-echo 与 dsflash-go 两类 Workbench 哨兵。fake-echo 验收要求同一 session 多轮 prompt 后,刷新、切换 away/back、deep link 和双观察者场景的 message role sequence 保持 `UAUA...`,不得出现 user cluster、session rail title fallback、cross-page projection divergence 或 activeSession/routeSession 漂移。dsflash-go 验收要求 trace rows 按 Workbench projectedSeq/aggregateSeq 单调,completion row 与 sealed final response 属于同一 trace/turn,终态 duration 不继续增长,Code Agent 卡片耗时、完成行耗时与 ReadModel timing 字段一致。关闭 issue 前,两个哨兵都必须连续 3 次通过或给出明确未通过 blocker;不得通过减少轮数、跳过刷新/切换步骤、提高 120s 预算、忽略 WBC-011/WBC-046/trace-row-order-nonmonotonic/timing mismatch,或在 probe/analyzer 侧补偿来判绿。
### 6.8 WB-PROJ-REQ-008 code reference rule
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-008 | 代码引用 | PJ2026-010401080308 CodeReference | [规格治理](spec-governance.md) |
本专项范围内新增或重构的核心源码文件,文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如:
Workbench 的唯一终态由替代规格定义,固定数据链为:
```text
SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p1-zero-split-durable-realtime
agentrun.event.v1
-> HWLAB mapper/direct publish
-> hwlab.event.v1
-> live SSE / Kafka retention replay SSE
-> 同一浏览器 reducer
```
同一文件同时承载 API契约、HWLAB接入、Web工作台或 Agent编排职责时,应在同一头部追加对应 SPEC 编号与实现引用版本。实现文件不得只写 issue 编号、`latest``current`。自动生成文件、第三方 vendored 文件、纯配置、锁文件和无法承载注释头的二进制产物可例外,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC
PostgreSQL 只可承载非阻塞派生读模型。数据库 schema、migration、transactional projector 和 projection outbox 均不得成为 prompt admission、Cloud API 启动、direct publish、live SSE、Kafka replay 或滚动上线的前置条件
### 6.9 WB-PROJ-REQ-009 derived read cache boundary
## 3. 禁止继续采用的旧思想
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-009 | 派生读缓存 | PJ2026-010401080309 DerivedReadCache | [Workbench性能](PJ2026-01060505-workbench-performance.md)、[API契约](PJ2026-010403-api-contract.md) |
- 禁止把 Workbench PostgreSQL aggregate event stream、facts、checkpoint 或 outbox 恢复为 Kafka 事件之前的 inline authority。
- 禁止要求 prompt admission 与本地 projection outbox 在同一事务提交。
- 禁止用数据库 outbox replay、`/v1/workbench/sync`、业务 REST 补链、页面轮询或读侧 repair 替代 Kafka retention replay。
- 禁止保留 direct/live 与 transactional projector 两套可切换 authority。
- 禁止因派生读模型 schema 缺失、迁移未执行或 projector 退化而返回 admission failure、关闭 Kafka 实时能力或阻塞服务启动。
- 禁止新增源码、测试、issue 或发布门禁继续引用本规格作为有效实现合同。
WorkbenchReadModel 可以使用 Redis 派生读缓存降低高频读路径的 Postgres 尾延迟,但缓存只保存可丢弃、可过期、可重建的 read model DTO 或内部 read snapshot。优先允许缓存 `/v1/workbench/sessions` actor-scoped session summary page、terminal turn snapshot 和 terminal trace event pagerunning turn、active session、projectionStatus 非 terminal 或正在变化的页面应使用更短 TTL 或不缓存。
## 4. 迁移规则
缓存 key 必须包含 schema version、cache key class、actor visibility input、sessionId/turnId/traceId/cursor、projection revision/seq 或等价 authority input。payload 不得包含 raw secret、Authorization header、cookie、DB DSN、完整 prompt、完整 provider payload、完整 stdout/stderr 或未脱敏身份信息。命中缓存前必须能确认 authority input 匹配;revision mismatch、decode failed、actor mismatch、stale 或 Redis unavailable 时,ReadModel 必须走 durable facts read 或返回结构化 degraded,不得把缓存内容作为 lifecycle、terminal、final response、not-found、deleted 或 archived 的判断依据
失效策略必须跟随 projection commit。Projection writer/finalizer 成功提交 session、turn 或 trace revision 后,应精确失效相关 key;若阶段上只能依赖短 TTL,自然过期策略必须与 user-visible freshness SLO 匹配,并通过 API/diagnostic 暴露 `cacheAgeMs` 和 projection revision/seq。Redis 中是否存在 key 不得用于推断 session lifecyclecanonical deleted、archived、not-found、running、completed、failed、blocked 和 final response 仍只能来自 durable Workbench facts。
派生缓存不能成为 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 detail 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 触发 SSE replay、统一 `/v1/workbench/sync` replay 或 transport diagnostic;不能在浏览器 reducer 内通过 arrival order 合成最终顺序,也不能调用 trace/session/turn 多端点补洞写主状态。
Timing 字段必须由 aggregate event stream 和 projector 统一产生。`startedAt` 来自 admission/source start event`lastEventAt` 来自最新已投影活动事件,`finishedAt``durationMs` 来自 terminal event 或等价 terminal resultbrowser 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 detail 晚到、SSE replay gap、cloud-api rolling restart 和浏览器 session 切换样本,证明完成行、final response、duration、trace page 和 session rail 均按 aggregate event stream revision 收敛。
### 6.11 WB-PROJ-REQ-011 CLI trace view and analyzer contract
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-011 | CLI视图 | PJ2026-010401080311 CliTraceView | [Web工作台](PJ2026-010401-web-workbench.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md)、[API契约](PJ2026-010403-api-contract.md) |
`web-probe collect/observe` 是唯一采样保存入口,负责按 5 到 10 秒级别采集 DOM/API/console/network 等事实,并把 frame、sample、request、traceId、runId、commandId 和时间戳写入采样目录。`web-probe analyze` 的 trace 截图是从这些采样事实或同源 read model 渲染出来的文字视图,不得另存一份“截图事实”,也不得在 analyze 阶段重新访问页面来补采样。
CLI 视图必须提供两层:第一层 `turn-summary` 展示多 turn 摘要,至少包含用户消息摘要、turn index、traceId、runId、commandId、status、elapsed、recent、warning 和最终内容摘要;第二层 `trace-frame` 按 turn、traceId、sample seq 或时间点渲染单 turn 的有序事件行。`trace-frame` 必须固定包含 `Final Response` 分区;running 或未 sealed 时显示 `(空内容)`terminal sealed 后显示 sealed final part 的实际内容。该分区不得从用户 prompt、backend diagnostic、中间 assistant text、steer accepted 文案或 DOM 最后一行回退。
Trace-frame 行顺序必须来自 Workbench projectedSeq、aggregateSeq、part order 或采样事实中的同源顺序字段;完成行、assistant part 和 diagnostic 行不得按 DOM 到达顺序、文本时间戳排序或 analyzer 私有排序重排。若同一 frame 中存在乱序、completion row 非最后、duration 不一致或缺少 order 字段,CLI 应直接标红或 warning,保留原始矛盾供人工判断,而不是把视图修正成看起来正确。
自动判别器必须以 CLI trace 视图为判据。finding 生成、降级和消除都要能在 `turn-summary``trace-frame` 中复核;不能只依赖机器规则把长期存在的问题误判为通过。任何单次 Workbench 操作、turn 投影、命令执行、finalizer catch-up、trace detail/history hydration 或 analyze 阶段超过 120 秒,都必须输出 severe timeout warning,并要求进一步调查;该 warning 不得被普通 poll retry、fallback route、自动刷新或 analyzer 补偿吞掉。
prompt、steer、cancel 和 retry 必须在 CLI 视图中保留 control command boundary。普通 prompt 的 POST `/v1/agent/chat`、运行中 steer 的 `/v1/agent/chat/steer`、cancel 的 `/v1/agent/chat/cancel`、以及 terminal/no-active no-op 必须分别显示 action、target turn/run/command、HTTP status、accepted/no-op/blocker 和相关 idsanalyzer 不得因为同一时间窗内出现 steer 请求就把此前 prompt 判定成 `prompt-routed-to-steer`
D518/v0.3 business trace closeout 必须能从 node/lane YAML 解析 AgentRun namespace、control-plane route 和 public origin,而不是硬编码 namespace 或依赖当前 kubectl context。`diagnose-code-agent --target D518` 或等价受控入口应输出 traceId、sessionId、runId、commandId、runner identity、projection/read span、OTel span 状态和 redacted namespace/endpoint 摘要;缺少 namespace、OTel span、trace frame 或 ReadModel digest 时,issue 不能仅凭 PR 合并或构建通过关闭。
### 6.12 WB-PROJ-REQ-012 serve/session aggregate authority
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| WB-PROJ-REQ-012 | 会话聚合权威 | PJ2026-010401080312 ServeSessionAggregate | [API契约](PJ2026-010403-api-contract.md)、[Agent编排](PJ2026-0102-agent-orchestration.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md) |
Workbench session 必须是用户可见执行状态的 aggregate root。prompt、steer、cancel 和 retry 先写成 durable input/command fact,再进入 AgentRun run/command、runner job 创建、steer delivery 或 cancel deliveryadmission route 只能返回 durable accepted、structured conflict、structured no-op 或 blocker,不得让浏览器请求等待 Kubernetes Job 创建、runner 启动、result polling 或 trace detail hydration。
每个 input/command fact 必须至少绑定 `sessionId``turnId``traceId``userMessageId``assistantMessageId``commandId`、action、target run/command、`admittedSeq``promotedSeq`、status、no-op reason 或 blocker。`turnId/traceId/messageId/partId` 必须在 dispatch 前或首次 projection commit 前稳定分配;后续 AgentRun event/result、steer accepted、cancel requested、terminal result 和 diagnostic 都必须回绑这些身份。提交 HTTP 500、AgentRun dispatch failure 或 delivery timeout 也必须绑定到本次 input fact,不得回落到旧 trace、旧 final response 或旧 active card。
同一 session 必须有一条受控 execution lane。wake、interrupt、steer、cancel、retry 和 runner terminal 之间必须按 session aggregate seq 判定新旧;stale wake、late runner event、旧 turn polling、DOM active card、session list summary、last trace row 或浏览器 local state 都不能覆盖更新 turn 的状态。没有 active turn 的 cancel/steer 必须返回结构化 no-op 或 error;已 terminal 的 cancel 必须返回 already-terminal/no-op 或触发 terminal projection catch-up,不能重新打开 sealed turn 或覆盖 terminal facts。
同一 session execution lane 必须有可审计的 AgentRun 承载机制。优先形态是同一个 AgentRun run 接收连续 command,并让已 claim 的 runner 在 idle timeout 内继续 poll 后续 command;若后续实现选择 session runner lease 或跨 run warm runner channel,也必须暴露稳定 session/channel/lease identity、command handoff、cancel/interrupt fencing 和 terminal diagnostic。仅在 `sessionPolicy`、metadata、thread id 或 PVC 上标记“reuse”,但每个 Workbench turn 都新建独立 run-scoped runner Job,不满足本要求,也不能作为 10x canary 或 120s 性能验收通过证据。
Message/part 是用户结果的显示权威。assistant final response 只能来自 sealed assistant final/text partdiagnostic、stdout/stderr、transport error、steer/cancel accepted 文案和 analyzer summary 必须分仓展示。trace rows、turn timing、session running、completion row 和 duration 必须从同一 session aggregate/event stream/read model 派生;`trace-frame --trace-id newTrace` 不得显示旧 trace 行。若缺少 order、缺少 terminal 或存在 projection 矛盾,CLI/API/Web 必须暴露 projection blocker 或 warning,而不是读侧补齐。
兼容 `/v1/agent/*`、conversation path、旧 Web route、CLI renderer、SSE 和 fake-server 都只能调用同一个 mutation/read model。保留 wrapper 时,它只能做鉴权、schema 映射和旧字段降级,不拥有第二套 prompt admission、status、final response、timing 或 trace authority。
本要求参考 OpenCode serve 的职责边界,但不复制其技术栈。HWLAB 应学习其 `SessionInput` admitted/promoted、session run coordinator、run-state、message/part event 和 abort route 分工:输入先成为可审计事件,run-state 集中仲裁 busy/idle/cancel/retrymessage/part 按顺序追加并 sealed,读取路径只消费 page/cursor/read model。后续实现不得继续沿用 trace tail、result envelope、DOM、session list 或 analyzer fallback 作为架构补丁。
## 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 侧补偿。
Workbench turn/message/trace 投影 authority 与 CLI trace 视图收敛的架构修复执行 issue 为 [#2079](https://github.com/pikasTech/HWLAB/issues/2079),正式 20 轮长程采样父 issue 为 [#2072](https://github.com/pikasTech/HWLAB/issues/2072),运行中 steer 与前 1-5 轮采样子 issue 为 [#2078](https://github.com/pikasTech/HWLAB/issues/2078)。后续实现必须引用 `draft-2026-06-24-p1-opencode-message-part-authority`,并在各阶段子 issue 中说明是否已经消除 final response 误选、turn-summary/trace-frame traceId 误归因、completion row 非最后、duration 不一致、prompt/steer/cancel 边界误判和 analyzer-only 误判。
Workbench serve/session aggregate authority 架构修复执行 issue 为 [#2125](https://github.com/pikasTech/HWLAB/issues/2125)。阶段跟踪必须以子 issue 为准:P0 SPEC-first [#2128](https://github.com/pikasTech/HWLAB/issues/2128)、P1 durable input/command 与 session aggregate seq [#2127](https://github.com/pikasTech/HWLAB/issues/2127)、P2 message/part/turn/trace read model 与 terminal atomic commit [#2126](https://github.com/pikasTech/HWLAB/issues/2126)、P3 prompt/steer/cancel run-state authority [#2129](https://github.com/pikasTech/HWLAB/issues/2129)、P4 REST/SSE/CLI/Web 单源消费与 legacy wrapper 降级 [#2131](https://github.com/pikasTech/HWLAB/issues/2131)、P5 删除 fallback/repair/renderer 补丁路径 [#2130](https://github.com/pikasTech/HWLAB/issues/2130)、P6 fake-server 与 D601/v03 20轮原入口验收 [#2132](https://github.com/pikasTech/HWLAB/issues/2132)。后续实现必须引用 `draft-2026-06-25-p0-serve-session-aggregate-authority`,并在关闭各阶段 issue 时说明 prompt admission、steer/cancel、run-state、message/part、trace/timing、final response 是否已经共享同一 session aggregate authority。
dsflash-go 10x canary 超过 120s、同一 Workbench session 连续 turn 创建多个独立 AgentRun runner/job、DOM trace rows 与后端 trace API 不一致的证据 issue 为 [#2171](https://github.com/pikasTech/HWLAB/issues/2171)。后续实现必须同时引用 `draft-2026-06-25-p0-session-warm-runner-contract`,并在 P1/P3/P6 closeout 中证明同一 session 的连续 turn 已进入同一 execution lane 或等价 warm runner/session command channel;若仍出现每 turn 新建 run-scoped runner Job,必须保持验收 red,而不是提高 120s 预算、减少轮数或用 renderer/probe fallback 掩盖。
D518 Workbench 会话 timeline 与刷新一致性执行 issue 为 [pikasTech/unidesk#1217](https://github.com/pikasTech/unidesk/issues/1217)。后续实现必须引用 `draft-2026-06-28-p0-d518-session-timeline-consistency`,并在 closeout 中回写 UniDesk SPEC PR、HWLAB v0.3 PR、D518 control-plane rollout commit/PipelineRun/Argo revision、fake-echo 与 dsflash-go 三连哨兵报告、OTel business trace 诊断、ReadModel role sequence/digest 证据,以及是否仍存在 session title fallback、cross-page divergence、trace row nonmonotonic 或 timing mismatch。
仍引用 `PJ2026-0104010803` 的实现与测试必须迁移到 `PJ2026-010401080313`。旧链接可以保留用于历史追溯,但任何与替代规格冲突的断言、schema 门禁、migration 依赖和 outbox 原子提交要求都必须删除,不做兼容保留
@@ -18,11 +18,12 @@
| 编号 | PJ2026-010401080313 |
| 短名 | Workbench实时权威 |
| 层级 | L4 专项规格切片 |
| 状态 | 草稿 |
| 状态 | 已生效 |
| 实现引用版本 | draft-2026-07-08-p0-workbench-realtime-authority-v2; draft-2026-07-09-p1-single-step-debug; draft-2026-07-14-p0-pure-kafka-authority |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md) |
| 关联规格 | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) |
| 废弃规格 | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) |
| 关联规格 | [PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文承载 Workbench Realtime Authority v2 的长期裁决。GitHub issue 记录阶段执行和证据;本文定义长期稳定的实时权威、禁止路径、回归和调试工作台边界。
@@ -55,7 +56,7 @@ PostgreSQL 可以保存查询优化所需的派生读模型,但不是 `agentru
### 2.3 范围外
- AgentRun run/command/runner job、provider stream 和 Code Agent 执行事实仍由 Agent编排定义。
- Durable event stream、projection writer/finalizer、facts store、read model 的写侧事务细节由 [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义
- PostgreSQL 派生读模型的内部存储细节不改变本规格的数据权威,也不得成为 admission、实时或回放链路的前置
- 浏览器内存、freeze blocker、RUM 和 web-probe 运行策略由 [PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md) 和 Web哨兵规格定义。
- 调试工作台不是用户业务入口,不拥有 session lifecycle、权限、Secret、真实 mutation 或运行面修复权。
@@ -19,10 +19,10 @@
| 短名 | 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; draft-2026-06-25-p0-web-caserun-e2e; draft-2026-06-25-p0-project-management-mdtodo; draft-2026-06-25-p0-mdtodo-web-active-editing-hwpod-source; draft-2026-06-27-p0-workbench-read-api-contract; 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; draft-2026-06-25-p0-serve-session-aggregate-authority; 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-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-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.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 契约的稳定使命、范围、术语、系统边界、内部分工和原子需求。
@@ -87,10 +87,10 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
| 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 事件。 |
| 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 streamAPI 只暴露其 projection revision、cursor 和 replay envelope,不得把 source event array 或 result envelope 作为第二 API 事实源。 |
| Serve Session Aggregate Authority | [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义的会话聚合权威;API mutation 先写 durable input/command factGET/SSE/compat wrapper 只读同一 aggregate projection。 |
| 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 streamAPI 只暴露其 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 或等价字段;它不参与业务状态判断。 |
@@ -121,19 +121,19 @@ API契约负责定义 Cloud Web、HWLAB CLI 和自动化脚本共同使用的 RE
| 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-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 factscompat wrapper 只提供旧 path 到新资源的兼容映射,不拥有第二套业务事实。
### 5.1 Workbench唯一投影 API 边界
### 5.1 Workbench实时权威 API 边界
[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 notificationcompat wrapper 只能调用同一 read model 或正式 mutation。
[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 必须接入 serve/session aggregate authority。`POST /v1/agent/chat`、steer、cancel、retry 或未来 `/v1/workbench/sessions/{sessionId}/turns` 等入口,应先写入 durable input/command fact 并短返回 `202 Accepted`、structured conflict、structured no-op 或 blocker;响应中必须包含可继续查询`sessionId``turnId``traceId``commandId` 或 no-op reason。API 不得把浏览器请求阻塞到 Kubernetes Job 创建、runner 启动、result pollingtrace hydration 或 finalizer catch-up,也不得在失败时把新提交回落到旧 session/trace/final。旧 `/v1/agent/*` wrapper 只能调用同一 mutation/read model 并做字段降级
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 pollingtrace hydration;派生读模型失败只能形成 warning/diagnostic,不能把已接纳命令改写为 admission failure
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 补洞
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。
@@ -292,7 +292,7 @@ Cancel mutation 在转发 AgentRun cancel 前必须核验本地 sealed terminal
Workbench read-model dependency timeout 必须返回结构化 degraded/readiness/blocker 响应;PostgreSQL pool connect/query timeout 不得作为未捕获异常杀死 cloud-api 进程,也不得让 liveness 因单次 Workbench read query 变成 EOF。
新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-010403 API契约 draft-2026-06-20-p0-workbench-pure-read-api; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0`,并简述文件职责。实现文件不得只写 issue 编号、`latest``current` 作为规格引用。
新增或重构的核心后端文件头部必须标注遵循的 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 资源与管理接口
@@ -355,7 +355,7 @@ Workbench 投影 blocker、proxy timeout、鉴权失败、provider profile、web
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| CLIENT-API-REQ-006 | 缓存诊断 | PJ2026-01040306 缓存诊断 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |
| 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 分仓。
@@ -77,7 +77,7 @@ AgentRun发布Lane负责定义 AgentRun `v0.1` 在 G14 上的专用发布 lane
| PJ2026-0106010502 | EnvImage | 本规格 6.2 | env image identity、digest-pinned image、work-ready 工具和 promotion | Source commit、registry、Containerfile | Runtime装配、runner job |
| PJ2026-0106010503 | CLI验收 | 本规格 6.3 | AgentRun CLI JSON、短返回、redaction 和正式命令入口 | AgentRun REST API | HWLAB 接入、队列会话 |
| PJ2026-0106010504 | 真实联调 | 本规格 6.4 | real provider turn、Postgres durable facts、SecretRef 和 terminal status | AgentRun核心、后端Profile | 发布判定 |
| PJ2026-0106010505 | Rolling验收 | 本规格 6.5 | manager/cloud-api rolling、runner 不中断、reconciler re-attach 和 Workbench projection recovery | AgentRun核心、HWLAB接入、Workbench唯一投影 | 发布判定、运维监控 |
| PJ2026-0106010505 | Rolling验收 | 本规格 6.5 | manager/cloud-api rolling、runner 不中断、reconciler re-attach 和 Workbench projection recovery | AgentRun核心、HWLAB接入、Workbench实时权威 | 发布判定、运维监控 |
## 6. 原子需求
@@ -125,7 +125,7 @@ mock backend、fake provider、source-only、dry-run、缺 provider credential
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| AR-RELEASE-REQ-005 | Rolling验收 | PJ2026-0106010505 Rolling验收 | [AgentRun核心](PJ2026-010201-agentrun-core.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[运维监控](PJ2026-010605-observability-monitoring.md) |
| AR-RELEASE-REQ-005 | Rolling验收 | PJ2026-0106010505 Rolling验收 | [AgentRun核心](PJ2026-010201-agentrun-core.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[运维监控](PJ2026-010605-observability-monitoring.md) |
AgentRun `v0.1` 发布验收应包含 rolling recovery canary。验收在 D601 v0.3 HWLAB 用户入口或等价受控 CLI 发起长程 Code Agent session,记录 `sessionId``traceId``runId``commandId``runnerJobId` 和 Kubernetes `jobName`runner 正在执行时滚动 HWLAB cloud-apirunner 继续执行时滚动 AgentRun manager。滚动结束后,同一 run/command/runnerJob 必须被 manager reconciler 恢复控制并进入 Workbench projection,不重建 run、不人工 resubmit、不切 session repair。
@@ -96,8 +96,8 @@
| PJ2026-01060504 | 边界约束 | 本规格 6.4 | 监控与业务通过、长证据、敏感输出的边界 | 全部 L1 | 用户反馈和排障 |
| PJ2026-01060505 | Workbench性能 | [PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) | Web 工作台用户可感知性能、RUM、AgentRun event visible latency 和 Prometheus 指标口径 | Web工作台、Agent编排、API契约 | 平台运维、客户端和性能回归调查 |
| PJ2026-01060506 | Metrics接入 | 本规格 6.6 | metrics endpoint、scrape target 和 label 口径 | 各 L1 服务健康指标 | Prometheus 查询 |
| PJ2026-01060507 | Rolling恢复观测 | 本规格 6.7 | active runner、reconciler backlog、terminal retry、projection lag 和不可恢复 blocker 的查询口径 | AgentRun核心、HWLAB接入、Workbench唯一投影、发布Lane | rolling 发布判定、故障收口 |
| PJ2026-01060508 | Web哨兵 | [PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) | `web-probe observe` 的 YAML-first 生产哨兵、独立 runner、中心 Monitor/Host PG、报告视图、dashboard 分析工作台和发布恢复验证 | Web工作台、Workbench唯一投影、YAML运维、公开入口、发布流水 | 平台值守、CI/CD targetValidation、用户入口恢复判定 |
| PJ2026-01060507 | Rolling恢复观测 | 本规格 6.7 | active runner、reconciler backlog、terminal retry、projection lag 和不可恢复 blocker 的查询口径 | AgentRun核心、HWLAB接入、Workbench实时权威、发布Lane | rolling 发布判定、故障收口 |
| PJ2026-01060508 | Web哨兵 | [PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) | `web-probe observe` 的 YAML-first 生产哨兵、独立 runner、中心 Monitor/Host PG、报告视图、dashboard 分析工作台和发布恢复验证 | Web工作台、Workbench实时权威、YAML运维、公开入口、发布流水 | 平台值守、CI/CD targetValidation、用户入口恢复判定 |
| PJ2026-01060509 | 出站诊断 | 本规格 6.9 | provider egress TCP tunnel、受控 relay、async job/server lifecycle 的阶段化日志、低噪声摘要和诊断入口 | provider-gateway、backend-core、YAML运维、发布流水 | D601/G14 runtime 出站排障、OpenFGA/Postgres/OA Event Flow 链路验收 |
## 6. 原子需求
@@ -255,7 +255,7 @@ Workbench 性能监控只记录低基数指标、阶段耗时、状态分类和
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-MON-REQ-007 | Rolling恢复 | PJ2026-01060507 Rolling恢复观测 | [AgentRun核心](PJ2026-010201-agentrun-core.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[AgentRun发布Lane](PJ2026-01060105-agentrun-v01-release-lane.md) |
| OPS-MON-REQ-007 | Rolling恢复 | PJ2026-01060507 Rolling恢复观测 | [AgentRun核心](PJ2026-010201-agentrun-core.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[AgentRun发布Lane](PJ2026-01060105-agentrun-v01-release-lane.md) |
运维监控应为 AgentRun/HWLAB rolling recovery 和 cancel lifecycle 提供可查询的低基数 metrics、trace span 和受控 CLI 摘要。最小观测对象包括 active runner 数、runner job observation phase、stale lease 数、cancel request accepted 数、cancel delivered 数、cancel terminalized 数、late-write-fenced 数、terminal report retry/outbox backlog、manager reconciler backlog、reconciler last success/error、projection lag、projection blocker 数、Job TTL cleanup 数和不可恢复 blocker 数。
@@ -267,7 +267,7 @@ rolling recovery 相关 span 应能用 OTel trace id/request id 关联 `sessionI
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-MON-REQ-008 | Web哨兵 | [PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) | [Web工作台](PJ2026-010401-web-workbench.md)、[Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md)、[公开入口](PJ2026-010604-public-entry.md)、[发布流水](PJ2026-010601-controlled-release.md) |
| OPS-MON-REQ-008 | Web哨兵 | [PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md) | [Web工作台](PJ2026-010401-web-workbench.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md)、[公开入口](PJ2026-010604-public-entry.md)、[发布流水](PJ2026-010601-controlled-release.md) |
运维监控应提供 YAML-first Web 哨兵能力,把现有 `web-probe observe start/status/command/collect/analyze` 服务化为生产可用的持续 canary、报告视图和发布恢复验证入口。该能力只 wrap 现有 observe runner、control queue、artifact JSONL、`collect` 渲染和 `observe analyze` 报告,不新增第二套 Playwright runner、offline analyzer、finding classifier、dashboard 事实源或 Workbench 状态机。
@@ -19,10 +19,10 @@
| 短名 | Workbench性能 |
| 层级 | L3 子课题 |
| 状态 | 已生效 |
| 实现引用版本 | 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 |
| 实现引用版本 | draft-2026-06-19-p0; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-22-p1-workbench-redis-derived-cache; PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority |
| 需求规格模板 | [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) |
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版:正文只保留 D601 v0.3 Workbench 用户可感知性能监控的稳定使命、范围、术语、系统边界、内部分工、目标图和原子需求。
@@ -65,7 +65,7 @@ Workbench timing 观测必须以唯一投影的 aggregate event stream revision
- Prometheus 具体采样间隔、保留周期、阈值、Grafana 面板 URL 和告警路由以 YAML/config 为准,不在本规格硬编码。
- 浏览器即时 probe、管理员手工 curl、后端日志 grep、Prometheus raw dump 或 synthetic check 不得作为 `/performance` 同一展示字段的替代权威;这些只能作为独立 metric family、定位证据或运维检查。
- 长 trace、完整 prompt、assistant 正文、tool 参数、命令输出、Secret、token、DSN 和原始 provider payload 不进入性能指标 label 或默认日志。
- Redis 不承载登录态、权限、OpenFGA、账本、AgentRun command/lease、runner 状态、session lifecycle 或 final response;这些事实分别归用户管理、Agent编排、Workbench唯一投影和对应 durable store。
- Redis 不承载登录态、权限、OpenFGA、账本、AgentRun command/lease、runner 状态、session lifecycle 或 final response;这些事实分别归用户管理、Agent编排、Workbench实时权威和对应 durable store。
## 3. 术语表
@@ -77,7 +77,7 @@ Workbench timing 观测必须以唯一投影的 aggregate event stream revision
| 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` 或等价字段表达;性能观测只能用它关联业务顺序和可见耗时,不得用本地采样到达顺序重排业务事实。 |
| 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 等后端阶段。 |
@@ -271,7 +271,7 @@ sequenceDiagram
U->>W: open workbench or select session tab
W->>W: start journey open/session_switch
W->>A: GET initial snapshot or /workbench/sync replay
W->>A: GET initial snapshot or Kafka replay SSE
A->>S: query session/message/turn projection
A->>T: query trace detail only when explicitly opened
A-->>W: first authoritative payload
@@ -299,10 +299,10 @@ session 切换必须分别记录 `first_visible` 和 `full_load`。first visible
| PJ2026-0106050508 | Dashboard可视化 | 本规格 6.8 | `/performance` 中文化图表、chart-ready summary、低基数维度、空态/错误态和表格 drill-down | Web工作台、API契约、运维监控 | D601 v0.3 Performance 原入口验收 |
| PJ2026-0106050509 | 权威观测 | 本规格 6.9 | observation history、metric family、windowed summary 和跨族不可覆盖边界 | 运维监控、Web工作台、API契约 | `/performance`、告警、审计 |
| PJ2026-0106050510 | 窗口质量 | 本规格 6.10 | 时间窗口、样本数、freshness、aggregationKind、approximation 和 lowSample 语义 | 运维监控、API契约 | dashboard、TopN、drill-down |
| PJ2026-0106050511 | 分叉禁令 | 本规格 6.11 | 禁止 collectorStatus 旁路、读侧 repair、fallback、bucket 上界冒充精确值和跨族仲裁 | Workbench唯一投影、Web工作台 | 后续迁移和回归 |
| PJ2026-0106050511 | 分叉禁令 | 本规格 6.11 | 禁止 collectorStatus 旁路、读侧 repair、fallback、bucket 上界冒充精确值和跨族仲裁 | Workbench实时权威、Web工作台 | 后续迁移和回归 |
| PJ2026-0106050512 | SLO治理 | 本规格 6.12 | SLO、阈值、告警准入、用户可见页面和内部告警职责分离 | 运维监控、YAML运维 | 持续治理和维护 issue |
| PJ2026-0106050513 | Redis读缓存 | 本规格 6.13 | Workbench Redis 派生读缓存的指标、SLO、YAML-first 参数和降级可见性 | Workbench唯一投影、API契约、YAML运维 | D601 v0.3 sessions/turn/trace 高频读降尾延迟 |
| PJ2026-0106050514 | Workbench实时运行面 | [PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md) | SSE、错误处理、队列、缓存、timeline、storage、scroll、health、OTel 和 Web 哨兵冻结探测的迁移边界 | Web工作台、Workbench唯一投影、API契约、Web哨兵、YAML运维 | JD01 Workbench 多轮卡死和请求风暴治理 |
| PJ2026-0106050513 | Redis读缓存 | 本规格 6.13 | Workbench Redis 派生读缓存的指标、SLO、YAML-first 参数和降级可见性 | Workbench实时权威、API契约、YAML运维 | D601 v0.3 sessions/turn/trace 高频读降尾延迟 |
| PJ2026-0106050514 | Workbench实时运行面 | [PJ2026-0106050514 Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md) | SSE、错误处理、队列、缓存、timeline、storage、scroll、health、OTel 和 Web 哨兵冻结探测的迁移边界 | Web工作台、Workbench实时权威、API契约、Web哨兵、YAML运维 | JD01 Workbench 多轮卡死和请求风暴治理 |
## 6. 原子需求
@@ -370,7 +370,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、web-probe 和 dashboard 源码文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-01060505 Workbench性能 draft-2026-06-19-p0; PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p0-aggregate-event-stream`,并用一句话说明文件职责。
本性能监控能力的实现必须先引用本规格,再进入代码变更。新增或修改的前端、后端、CLI/helper、metrics、RUM、trace adapter、web-probe 和 dashboard 源码文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-01060505 Workbench性能 draft-2026-06-19-p0; PJ2026-010401080313 Workbench实时权威 draft-2026-06-24-p0-aggregate-event-stream`,并用一句话说明文件职责。
实现文件不得只写 issue 编号、`latest``current` 或“按最新方案”作为规格引用。自动生成文件、第三方 vendored 文件、纯 YAML/config、锁文件和无法承载注释头的二进制产物不要求加源码头部,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC。
@@ -380,7 +380,7 @@ UniDesk CLI 应提供薄 domain 入口,例如 `hwlab nodes observability plan|
| --- | --- | --- | --- |
| OPS-WBPERF-REQ-007 | TurnStatus预算 | PJ2026-0106050507 TurnStatus预算 | [API契约](PJ2026-010403-api-contract.md)、[HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[Agent编排](PJ2026-0102-agent-orchestration.md)、[Web工作台](PJ2026-010401-web-workbench.md) |
`/v1/agent/turns/:traceId` 属于旧 compat/diagnostic 读取面,不再是 Workbench 主消息运行态的 poll 权威入口。Workbench 主状态的 live/恢复权威来自 initial snapshot`/v1/workbench/events` typed event 和统一 `/v1/workbench/sync` replaytrace/detail 读取只能解释过程或诊断,不能覆盖 message finalResponse、turn terminal 或 session running。
`/v1/agent/turns/:traceId` 属于旧 compat/diagnostic 读取面,不再是 Workbench 主消息运行态的 poll 权威入口。Workbench 主状态的 live/恢复权威来自 initial snapshot`hwlab.event.v1` live/replay SSEtrace/detail 读取只能解释过程或诊断,不能覆盖 message finalResponse、turn terminal 或 session running。
Cloud API 如保留旧 turn status 或 trace detail 请求内的上游刷新尝试,刷新必须有独立的短预算;预算、开关和后续调整必须来自 YAML/env 配置,不得把具体数值写成第二真相。预算耗尽时,API 应返回已有快照并标记 `turn_status_degraded``agentrun_result_poll_failed``trace_refresh_timeout` 或等价低基数错误,后续 SSE、sync replay 或后台 projector 仍可继续补齐最新事件。除非权限不匹配、trace 不存在或请求参数非法,旧 diagnostic/detail 请求不应因为上游刷新慢而让 Web 客户端超时,也不得被前端用作 automatic repair authority。
@@ -438,7 +438,7 @@ Metric family 可以在同一页面中并列展示和关联 drill-down,但不
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-WBPERF-REQ-011 | 分叉禁令 | PJ2026-0106050511 分叉禁令 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[API契约](PJ2026-010403-api-contract.md) |
| OPS-WBPERF-REQ-011 | 分叉禁令 | PJ2026-0106050511 分叉禁令 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[Web工作台](PJ2026-010401-web-workbench.md)、[API契约](PJ2026-010403-api-contract.md) |
Performance 页必须吸收 Workbench 唯一投影的失败教训:不得在 Web reducer、summary API、fake-server、probe 脚本或 dashboard 组件中保留多个事实源,再通过“优先级、覆盖、fallback、字段缺失时改走另一端点、刷新后 repair、测试专用后门”等方式决定展示状态。字段缺失、投影滞后、采集失败或样本不足时,必须暴露数据质量或 blocker,并修 observation writer、aggregator、read model 或正式 API 契约。
@@ -464,7 +464,7 @@ Workbench 性能 SLO 只能基于稳定 metric family、明确窗口、足够样
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-WBPERF-REQ-013 | Redis读缓存 | PJ2026-0106050513 Redis读缓存 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[API契约](PJ2026-010403-api-contract.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md) |
| OPS-WBPERF-REQ-013 | Redis读缓存 | PJ2026-0106050513 Redis读缓存 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[API契约](PJ2026-010403-api-contract.md)、[YAML运维](PJ2026-010603-yaml-first-ops.md) |
D601 v0.3 Workbench 可以在 `hwlab-v03` namespace 内使用 Workbench 专用 Redis 作为派生读缓存,用于降低 `/v1/workbench/sessions`、terminal turn snapshot 和 terminal trace page 等高频读路径的远端 Postgres 重复查询和尾延迟。Redis 只缓存从 durable Workbench projection 派生出的短 TTL 快照;cache key 必须包含 schema version、cache key class、actor visibility input、session/turn/trace/cursor 和 projection revision/seq 或等价 authority input。
@@ -476,6 +476,6 @@ D601 v0.3 Workbench 可以在 `hwlab-v03` namespace 内使用 Workbench 专用 R
## 7. 过程控制
本规格的执行 issue 为 [#1392](https://github.com/pikasTech/HWLAB/issues/1392),性能问题修复执行 issue 为 [#1422](https://github.com/pikasTech/HWLAB/issues/1422)Performance dashboard 中文化可视化执行 issue 为 [#1609](https://github.com/pikasTech/HWLAB/issues/1609)。单一权威观测模型架构治理 issue 为 [#1638](https://github.com/pikasTech/HWLAB/issues/1638),阶段执行 issue 为 P0 [#1639](https://github.com/pikasTech/HWLAB/issues/1639)、P1 [#1641](https://github.com/pikasTech/HWLAB/issues/1641)、P2 [#1640](https://github.com/pikasTech/HWLAB/issues/1640)、P3 [#1642](https://github.com/pikasTech/HWLAB/issues/1642)、P4 [#1643](https://github.com/pikasTech/HWLAB/issues/1643) 和 P5 [#1644](https://github.com/pikasTech/HWLAB/issues/1644)。Workbench Redis 派生读缓存架构执行 issue 为 [#1870](https://github.com/pikasTech/HWLAB/issues/1870)P0 SPEC-first 子 issue 为 [#1871](https://github.com/pikasTech/HWLAB/issues/1871)。该类 issue 的 P0 阶段必须以本 SPEC 为前置:先确认本规格、父级 [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) 的引用关系,再进入后续实现。
本规格的执行 issue 为 [#1392](https://github.com/pikasTech/HWLAB/issues/1392),性能问题修复执行 issue 为 [#1422](https://github.com/pikasTech/HWLAB/issues/1422)Performance dashboard 中文化可视化执行 issue 为 [#1609](https://github.com/pikasTech/HWLAB/issues/1609)。单一权威观测模型架构治理 issue 为 [#1638](https://github.com/pikasTech/HWLAB/issues/1638),阶段执行 issue 为 P0 [#1639](https://github.com/pikasTech/HWLAB/issues/1639)、P1 [#1641](https://github.com/pikasTech/HWLAB/issues/1641)、P2 [#1640](https://github.com/pikasTech/HWLAB/issues/1640)、P3 [#1642](https://github.com/pikasTech/HWLAB/issues/1642)、P4 [#1643](https://github.com/pikasTech/HWLAB/issues/1643) 和 P5 [#1644](https://github.com/pikasTech/HWLAB/issues/1644)。Workbench Redis 派生读缓存架构执行 issue 为 [#1870](https://github.com/pikasTech/HWLAB/issues/1870)P0 SPEC-first 子 issue 为 [#1871](https://github.com/pikasTech/HWLAB/issues/1871)。该类 issue 的 P0 阶段必须以本 SPEC 为前置:先确认本规格、父级 [PJ2026-010605 运维监控](PJ2026-010605-observability-monitoring.md)、[PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 和 [PJ2026-010403 API契约](PJ2026-010403-api-contract.md) 的引用关系,再进入后续实现。
后续实现 issue 或 PR 收口时必须回写:使用的 SPEC 编号和实现引用版本、触达的源码文件头部标注情况、Prometheus 指标/label 审查结果、D601 v0.3 public origin 的原入口验证结果,以及是否需要继续修订本规格。
@@ -22,25 +22,25 @@
| 实现引用版本 | draft-2026-06-30-p0-1297-spec-first; PJ2026-010401080313 Workbench实时权威 draft-2026-07-08-p0-workbench-realtime-authority-v2 |
| 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) |
| 上级规格 | [PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md)、[PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md) |
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-01060508 Web哨兵](PJ2026-01060508-web-probe-sentinel.md)、[PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文定义 Workbench 浏览器实时运行面的迁移边界:SSE、统一 sync replay、错误处理、限流/队列、缓存、timeline、storage、scroll、health、OTel 与 Web 哨兵冻结探测必须用同一组受控语义协作。实时事实权威、禁止前端多源补洞和单步调试工作台以 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 为准;本文只定义浏览器运行面、队列、性能和 no-probe-masking 规则。
本文定义 Workbench 浏览器实时运行面的迁移边界:SSE、Kafka retention replay、错误处理、限流/队列、缓存、timeline、storage、scroll、health、OTel 与 Web 哨兵冻结探测必须用同一组受控语义协作。实时事实权威、禁止前端多源补洞和单步调试工作台以 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 为准;本文只定义浏览器运行面、队列、性能和 no-probe-masking 规则。
## 2. 目的和范围
### 2.1 目的
Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、SSE typed event、统一 `/v1/workbench/sync` replay、initial snapshot、trace/detail 只读投影、可见性诊断和 Web 哨兵采样收敛为可控、可观测、可回归的运行链路。目标是解除第二轮消息后页面卡死、浏览器内存无界上涨、SSE error 引发请求风暴、刷新后消息堆叠、跨 session/trace 串线和 monitor 只能看到症状看不到根因的问题。
Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、SSE typed event、Kafka retention replay SSE、initial snapshot、trace/detail 只读投影、可见性诊断和 Web 哨兵采样收敛为可控、可观测、可回归的运行链路。目标是解除第二轮消息后页面卡死、浏览器内存无界上涨、SSE error 引发请求风暴、刷新后消息堆叠、跨 session/trace 串线和 monitor 只能看到症状看不到根因的问题。
本专项采用 OpenCode serve 的边界作为对照:事件流负责 replay 和 ordering统一 sync replay 负责按 durable cursor 追平,REST detail/history 只负责显式详情和历史分页,错误 envelope 统一诊断,队列/single-flight 限制重复工作,timeline row model 保持稳定 identity。可整模块迁移的 TypeScript 策略模块必须先按 OpenCode 原文件或原核心函数机械拷贝,再在拷贝件上做 Vue/HWLAB 适配;禁止只阅读 OpenCode 后重写一个薄 wrapper 或只覆盖 happy path。Solid/Effect/TanStack 等框架专属层不直接搬运,但其状态机、分支语义、错误处理和 row/queue/transport 边界必须在 HWLAB runtime 中逐项保真。
本专项采用 OpenCode serve 的边界作为对照:事件流负责 replay 和 orderingKafka retention replay 负责按 durable cursor 追平,REST detail/history 只负责显式详情和历史分页,错误 envelope 统一诊断,队列/single-flight 限制重复工作,timeline row model 保持稳定 identity。可整模块迁移的 TypeScript 策略模块必须先按 OpenCode 原文件或原核心函数机械拷贝,再在拷贝件上做 Vue/HWLAB 适配;禁止只阅读 OpenCode 后重写一个薄 wrapper 或只覆盖 happy path。Solid/Effect/TanStack 等框架专属层不直接搬运,但其状态机、分支语义、错误处理和 row/queue/transport 边界必须在 HWLAB runtime 中逐项保真。
所有可调参数必须来自 YAML/source-of-truth 或其前端 runtime projection。本文和源码只定义字段族、状态机、责任边界和验收读取方式;不得写入硬编码阈值、采样周期、重试次数、并发数、缓存容量、退避窗口、超时窗口或浏览器内存 kill 数值。
### 2.2 范围内
- Workbench 浏览器 typed error、diagnostic envelope 和用户可见错误归一化。
- SSE runtime、cursor replay、sync replay、gap 分类、transport state 和 recovery action。
- SSE runtime、cursor replay、Kafka replay、gap 分类、transport state 和 recovery action。
- event coalescing、keyed single-flight、bounded refresh queue、prefetch/cache trimming 和 scoped key。
- message/part/timeline row model、刷新恢复、增量归一化和 DOM row identity。
- localStorage/sessionStorage 容错、namespace 迁移、quota/security exception 降级和可观测 storage failure。
@@ -53,7 +53,7 @@ Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、
### 2.3 范围外
- Workbench durable facts、message/part authority、terminal final response 和 read model 写侧仍由 [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义。
- Workbench durable facts、message/part authority、terminal final response 和 read model 写侧仍由 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义。
- AgentRun run/command/runner job、provider profile 和 backend execution lifecycle 不由本专项重新定义。
- 具体 YAML 路径下的参数数值、Secret、runtime image、node/lane、namespace、public origin 和 rollout 策略不在本文硬编码。
- Web 哨兵不负责修复业务投影;它只负责采样、分类、保存证据、报红和暴露根因入口。
@@ -64,8 +64,8 @@ Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、
| --- | --- |
| 实时运行面 | Workbench 浏览器侧从用户动作到 REST/SSE/read model/timeline/DOM 可见性/诊断的运行链路。 |
| typed error | 带 code、layer、category、route、traceId、requestId、retryable 和 diagnostic 的标准错误对象。 |
| transport state | SSE/EventSource 与统一 sync replay 的连接、打开、错误、关闭、replay、degraded 和 blocked 状态。 |
| recovery action | transport state 变化后允许触发的受控动作,例如继续 SSE replay、请求 `/v1/workbench/sync`、标记 degraded 或直接 blocked;动作不得绕过 queue/single-flight,也不得回退到 trace/session/turn 多端点补洞。 |
| transport state | SSE/EventSource 与Kafka retention replay 的连接、打开、错误、关闭、replay、degraded 和 blocked 状态。 |
| recovery action | transport state 变化后允许触发的受控动作,例如继续 Kafka retention replay SSE、标记 degraded 或直接 blocked;动作不得触发 `/v1/workbench/sync` trace/session/turn 多端点补洞。 |
| refresh queue | Workbench 前端聚合 REST refresh 请求的队列,按 scope/key 去重、限流、标记原因并输出诊断。 |
| scoped key | 由 node/lane/user/session/trace/message/part 等 authority id 归一化后的键,用于 cache、queue、storage、row identity 和 OTel 属性。 |
| timeline row model | 面向 Vue 渲染的稳定行模型,把 message、part、diagnostic、trace summary 和 gap placeholder 表达为可增量替换的 row。 |
@@ -73,7 +73,7 @@ Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、
| browser memory policy | YAML/source-of-truth 下发给 web-probe 或 runtime 的浏览器内存观测与 kill 策略;本文只定义字段语义,不定义数值。 |
| REST 风暴 | 同一用户动作或 transport 错误导致 `/sessions``/messages``/turns``/traceEvents``/health` 等请求族无界重复或互相触发的状态。 |
| 架构退化修复 | 为了让 smoke、dashboard 或哨兵变绿而改变探针、刷新策略、fallback、采样强度或错误等级,却没有修复 Workbench runtime/projection/read model 根因的行为;本专项禁止该模式。 |
| 单步调试工作台 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的独立 debug route,用 fake SSE/sync/detail fixture 单步驱动 reducer,不触发真实 Workbench mutation 或 automatic recovery。 |
| 单步调试工作台 | [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义的独立 debug route,用 fake live/replay SSE 与 detail fixture 单步驱动 reducer,不触发真实 Workbench mutation 或 automatic recovery。 |
## 4. 系统边界和接口
@@ -90,8 +90,8 @@ Workbench实时运行面负责把浏览器侧多轮 Workbench 的实时输入、
| 编号 | 内部模块 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
| --- | --- | --- | --- | --- | --- |
| PJ2026-010605051401 | ErrorRuntime | 本规格 6.1 | typed error、diagnostic envelope、用户可见错误和 OTel 关联 | API契约、Workbench唯一投影 | Workbench store、diagnostic panel |
| PJ2026-010605051402 | QueueRuntime | 本规格 6.2 | coalesced event queue、keyed single-flight、sync replay queue 和 prefetch/cache trimming | YAML运维、Workbench性能、Workbench实时权威 | SSE、sync replay、请求风暴治理 |
| PJ2026-010605051401 | ErrorRuntime | 本规格 6.1 | typed error、diagnostic envelope、用户可见错误和 OTel 关联 | API契约、Workbench实时权威 | Workbench store、diagnostic panel |
| PJ2026-010605051402 | QueueRuntime | 本规格 6.2 | coalesced event queue、keyed single-flight、Kafka replay queue 和 prefetch/cache trimming | YAML运维、Workbench性能、Workbench实时权威 | SSE、Kafka replay、请求风暴治理 |
| PJ2026-010605051403 | SseRuntime | 本规格 6.3 | EventSource lifecycle、cursor replay、transport state、gap 分类和 recovery action | API契约、唯一投影 | timeline、web-probe、OTel |
| PJ2026-010605051404 | TimelineRuntime | 本规格 6.4 | message/part 增量归一化、row identity、刷新恢复和跨 session/trace 隔离 | Web工作台、唯一投影 | Vue timeline、scroll、probe analyzer |
| PJ2026-010605051405 | BrowserRuntime | 本规格 6.5 | storage 容错、scroll 稳定、pane 滚动、health 探测和 local state 诊断 | Web工作台、YAML运维 | 用户体验、freeze 复现 |
@@ -162,7 +162,7 @@ flowchart LR
flowchart TD
U[用户消息或 session 切换] --> K[scoped key]
K --> Q[refresh queue / single-flight]
Q --> R[initial snapshot or /workbench/sync replay]
Q --> R[initial snapshot or /workbench/Kafka replay]
Q --> E[SSE subscribe with cursor]
E --> C[event coalescing]
C --> S[server-state reducer]
@@ -177,7 +177,7 @@ flowchart TD
O --> P[web-probe / monitor evidence]
```
同一用户动作只能通过 scoped key 进入受控 queueSSE error、visibility change、health probe 或 storage failure 只能产生 diagnostic 和受控 recovery action。允许的 live recovery 是 SSE replay 或 `/v1/workbench/sync`,不能绕过 queue 直接触发 session/message/turn/trace 多端点 fan-out。
同一用户动作只能通过 scoped key 进入受控 queueSSE error、visibility change、health probe 或 storage failure 只能产生 diagnostic 和受控 recovery action。允许的 live recovery 只有 Kafka retention replay SSE;禁止调用 `/v1/workbench/sync` session/message/turn/trace 多端点 fan-out。
### 5.3 SSE gap 与阻塞时序图
@@ -198,7 +198,7 @@ sequenceDiagram
S-->>S: transport error or seq gap
S->>O: transport diagnostic
S->>Q: allowed recovery action
Q->>A: bounded /workbench/sync replay when policy allows
Q->>A: bounded /workbench/Kafka replay when policy allows
P->>W: sample responsiveness and browser memory
P->>O: freeze/memory evidence
P-->>P: kill browser and mark blocked when policy says blocked
@@ -210,8 +210,8 @@ sequenceDiagram
| --- | --- | --- |
| OPS-WBRT-REQ-001 | ConfigSource | Workbench realtime、refresh queue、cache、storage、health、browser memory、freeze、sentinel cadence 和 smoke policy 的所有可调参数必须来自 YAML/source-of-truth 或其前端 runtime projection;源码和 SPEC 不得保存第二份数值真相。 |
| OPS-WBRT-REQ-002 | ErrorRuntime | 浏览器侧所有 REST/SSE/storage/health/projection 错误必须归一化为 typed error,并保留 layer、category、route、retryable、traceId/requestId 和 redaction 状态。 |
| OPS-WBRT-REQ-003 | QueueRuntime | SSE event、sync replay、explicit snapshot/detail/history、prefetch 和 health probe 必须通过 key 去重、single-flight 或 coalesced queue;同一错误路径不得产生无界 REST fan-out。 |
| OPS-WBRT-REQ-004 | SseRuntime | SSE runtime 必须以 server cursor/replay 为同步 authoritylive recovery 只允许 SSE replay、统一 `/v1/workbench/sync` replay 或 diagnostic,不得在 SSE error 中全量刷新多个请求族来“补洞”。 |
| OPS-WBRT-REQ-003 | QueueRuntime | SSE event、Kafka replay、explicit snapshot/detail/history、prefetch 和 health probe 必须通过 key 去重、single-flight 或 coalesced queue;同一错误路径不得产生无界 REST fan-out。 |
| OPS-WBRT-REQ-004 | SseRuntime | SSE runtime 必须以 server cursor/replay 为同步 authoritylive recovery 只允许 SSE replay、Kafka retention replay SSE 或 diagnostic,不得在 SSE error 中全量刷新多个请求族来“补洞”。 |
| OPS-WBRT-REQ-005 | TimelineRuntime | timeline 渲染必须基于稳定 message/part/row identity;刷新、SSE snapshot、trace event 和 REST page 替换不能造成用户消息堆叠、agent message 重复或跨 session/trace 串线。 |
| OPS-WBRT-REQ-006 | BrowserRuntime | storage、scroll、pane layout 和 health probe 的失败只能写入 diagnostic 或受控 recovery action;不得通过 reload、fallback、localStorage truth 或 document 级无限滚动掩盖状态分裂。 |
| OPS-WBRT-REQ-007 | SentinelFreeze | web-probe 必须把浏览器无响应和浏览器内存超过受控 policy 的状态分类为 blocker red,并保存 memory sample、freeze sample、request family、trace/span 和截图/日志证据;触发 blocker 后必须杀死浏览器,不得自动刷新页面或降级为 fallback。 |
@@ -221,7 +221,7 @@ sequenceDiagram
| OPS-WBRT-REQ-011 | MechanicalCopy | 可迁移的 OpenCode 通用模块必须先机械拷贝再适配;closeout 必须记录 OpenCode 来源行号、HWLAB 拷贝后行号、适配 diff 范围、被保留/删除/改名的能力清单,以及不存在“参考后重写”的复查结论。 |
| OPS-WBRT-REQ-012 | ShrinkageReview | 缩水是独立 P0 缺口;如果迁移后模块缺少 OpenCode 原有状态机、错误处理、限流/防抖、SSE/reducer、scroll persistence、timeline row parity 或 root cause 输出,即使生产路径已经 import,也不得判定完成。 |
| OPS-WBRT-REQ-013 | AppFixBoundary | 请求风暴、浏览器卡死、内存上涨、final response 投影缺失和刷新堆叠的修复必须落在 Workbench runtime、projection writer/finalizer、read model、SSE/REST contract、Vue store/reducer 或本专项迁移的共享模块;web-probe/Playwright 只能增强证据、baseline、blocker red 和 report 可见性,不能作为业务修复点。 |
| OPS-WBRT-REQ-014 | RequestStormRegression | 所有 SSE error、visibility change、health probe、explicit snapshot/detail/history 读取和 sync replay 都必须携带 scoped key、原因、in-flight/dedup 诊断和 recovery action;同一 scoped key 的重复恢复必须被 queue/single-flight 合并或阻塞,不能跨请求族递归触发。 |
| OPS-WBRT-REQ-014 | RequestStormRegression | 所有 SSE error、visibility change、health probe、explicit snapshot/detail/history 读取和 Kafka replay 都必须携带 scoped key、原因、in-flight/dedup 诊断和 recovery action;同一 scoped key 的重复恢复必须被 queue/single-flight 合并或阻塞,不能跨请求族递归触发。 |
| OPS-WBRT-REQ-015 | EvidenceSplit | closeout 必须区分 provider/AgentRun 执行完成、Workbench projection 完成和浏览器可见完成。OTel 显示 completed 但 UI trace rows/final response 为空时,应归入 read model/projection/runtime 可见性问题继续调查;不得把 completed trace 的空 UI 重新归因成 provider 失败,也不得用 analyzer fallback 生成假的 final response。 |
| OPS-WBRT-REQ-016 | NoProbeMasking | web-probe smoke 的目标是用户指定业务入口。为通过 smoke 而减少轮次、禁用内存/freeze 检测、自动 reload、重建页面、关闭 network 采样、吞掉 submit/command 失败或把 blocker red 降级为 warning,都属于架构退化。 |
| OPS-WBRT-REQ-017 | SingleStepDebug | Workbench 必须支持隔离的 fake SSE/sync/detail 单步调试工作台,用于验证 authority gate、sealed guard、detail-only rejection、cursor/reconnect 和 cross-page convergence;纯 SSE 模式下任何 automatic `/sync` 或旧 detail fan-out 都必须红灯。 |
@@ -231,7 +231,7 @@ sequenceDiagram
新增或修改的 HWLAB Cloud Web、Cloud API、web-probe、monitor、OTel 和相关测试源码文件头部必须引用本规格,例如:
```text
SPEC: PJ2026-0106050514 Workbench实时运行面 draft-2026-06-30-p0-1297-spec-first; PJ2026-0104010803 Workbench唯一投影 <实现引用版本>.
SPEC: PJ2026-0106050514 Workbench实时运行面 draft-2026-06-30-p0-1297-spec-first; PJ2026-010401080313 Workbench实时权威 <实现引用版本>.
```
自动生成文件、锁文件、第三方 vendored 文件和不能承载注释头的二进制产物不要求源码头部,但生成器、渲染器或配置入口必须能追溯到本规格。
@@ -267,8 +267,8 @@ Workbench 请求风暴或浏览器 freeze 类 issue 的关闭证据必须同时
| 编号 | 迁移模块 | OpenCode 对照能力 | HWLAB 目标接入点 | 完成口径 |
| --- | --- | --- | --- | --- |
| M01 | ErrorRuntime | typed error、diagnostic envelope、用户可见错误 | `web/hwlab-cloud-web/src/utils/workbench-error-runtime.ts`、Workbench store、消息面板 | REST/SSE/storage/health/projection 错误统一归一化并暴露 root cause/recovery action |
| M02 | RefreshQueueRuntime | queue、single-flight、cooldown、请求风暴抑制 | `workbench-refresh-runtime.ts``src/stores/workbench.ts` | sync replay、explicit snapshot/detail/history、health probe 进入同一 keyed queue |
| M03 | SseTransportRuntime | EventSource lifecycle、cursor、gap 分类 | `workbench-stream-transport.ts`、Workbench store | SSE reconnect 只触发 SSE replay、`/workbench/sync` 或 diagnostic,不触发旧 REST fan-out |
| M02 | RefreshQueueRuntime | queue、single-flight、cooldown、请求风暴抑制 | `workbench-refresh-runtime.ts``src/stores/workbench.ts` | Kafka replay、explicit snapshot/detail/history、health probe 进入同一 keyed queue |
| M03 | SseTransportRuntime | EventSource lifecycle、cursor、gap 分类 | `workbench-stream-transport.ts`、Workbench store | SSE reconnect 只触发 Kafka retention replay SSE 或 diagnostic,不触发 `/workbench/sync` 旧 REST fan-out |
| M04 | ScopedKeyRuntime | scope key、cache key、trace key | `workbench-key.ts`、store/runtime modules | session/trace/message/part 的 key 生成规则生产路径共用 |
| M05 | TimelineRuntime | 稳定 row identity、增量替换、跨 session 隔离 | server-state reducer、timeline composables、Vue message rendering | 刷新和第二轮消息不产生堆叠、重复或串线 |
| M06 | StorageRuntime | safe storage、namespace、quota/security 降级 | `workbench-storage-runtime.ts`、store、session rail | localStorage/sessionStorage 访问不再直接散落在组件和 store |
@@ -30,7 +30,7 @@
| 浏览器资源治理实现引用版本 | draft-2026-07-13-p18-browser-resource-guard |
| 需求规格模板 | [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-010601 发布流水](PJ2026-010601-controlled-release.md)、[PJ2026-010602 源码同步](PJ2026-010602-source-sync.md)、[PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md)、[PJ2026-010604 公开入口](PJ2026-010604-public-entry.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
| 关联规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md)、[PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010601 发布流水](PJ2026-010601-controlled-release.md)、[PJ2026-010602 源码同步](PJ2026-010602-source-sync.md)、[PJ2026-010603 YAML运维](PJ2026-010603-yaml-first-ops.md)、[PJ2026-010604 公开入口](PJ2026-010604-public-entry.md)、[PJ2026-01060505 Workbench性能](PJ2026-01060505-workbench-performance.md) |
| 规格治理索引 | [规格治理](spec-governance.md) |
本文采用 ISO/IEC/IEEE 29148 需求规格模板的项目裁剪版:正文只保留 Web 哨兵的稳定使命、范围、术语、系统边界、内部分工、目标图和原子需求。Web 哨兵是现有 `web-probe observe` 能力的生产化运行形态,不是新的探针实现。
@@ -61,7 +61,7 @@ Web哨兵必须遵循 UniDesk YAML-first ops。目标 node/lane、public origin
### 2.3 范围外
- Workbench 会话、message/part、Trace 顺序、final response、steer/cancel 和 timing authority 的业务正确性仍由 [PJ2026-0104010803 Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 定义。
- Workbench 会话、message/part、Trace 顺序、final response、steer/cancel 和 timing authority 的业务正确性仍由 [PJ2026-010401080313 Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 定义。
- AgentRun run/command/provider profile 的执行生命周期归 [PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) 和 [PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md)。
- API path、错误 envelope、route policy 和用户身份语义归 [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)。
- 第一阶段不交付分布式压测;loadtest 只保留同镜像、同 wrapper 的配置和命令扩展点。
@@ -120,10 +120,10 @@ Web哨兵必须遵循 UniDesk YAML-first ops。目标 node/lane、public origin
| 编号 | 内部模块 | 规格文档 | 主责边界 | 上游依赖 | 下游支撑 |
| --- | --- | --- | --- | --- | --- |
| PJ2026-0106050801 | Wrapper边界 | 本规格 6.1 | 只 wrap 现有 observe CLI,禁止第二 runner/analyzer | web-probe observe、Workbench唯一投影 | 服务化入口、人工排障 |
| PJ2026-0106050801 | Wrapper边界 | 本规格 6.1 | 只 wrap 现有 observe CLI,禁止第二 runner/analyzer | web-probe observe、Workbench实时权威 | 服务化入口、人工排障 |
| PJ2026-0106050802 | YAML配置 | 本规格 6.2 | configRefs、owning YAML、parser 校验和 redacted plan | YAML运维、公开入口、Secret分发 | plan/status、部署渲染 |
| PJ2026-0106050803 | 常驻服务 | 本规格 6.3 | scheduler、scenario runner、artifact PVC、中心 ingest/query、Host PG、health、metrics、maintenance API | Wrapper边界、YAML配置 | dashboard、CI/CD |
| PJ2026-0106050804 | 报告视图 | 本规格 6.4 | CLI/report API 渐进读取、分页、redaction、trace-frame | observe collect/analyze、Workbench唯一投影 | issue evidence、dashboard |
| PJ2026-0106050804 | 报告视图 | 本规格 6.4 | CLI/report API 渐进读取、分页、redaction、trace-frame | observe collect/analyze、Workbench实时权威 | issue evidence、dashboard |
| PJ2026-0106050805 | 发布集成 | 本规格 6.5 | CI/CD、GitOps、Argo、maintenance、targetValidation、publicExposure | 发布流水、源码同步、公开入口 | 发布恢复判定 |
| PJ2026-0106050806 | Canary验收 | 本规格 6.6 | dsflash-go 十轮工具调用、24 小时 dry-run 和 profile 结构化失败边界 | Agent编排、Workbench、web-probe | 生产巡检收口 |
| PJ2026-0106050807 | 安全隔离 | 本规格 6.7 | Secret/prompt/provider redaction、NetworkPolicy、public dashboard auth | 用户管理、平台运维 | 安全 closeout |
@@ -475,7 +475,7 @@ sequenceDiagram
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-001 | Wrapper边界 | PJ2026-0106050801 Wrapper边界 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Web工作台](PJ2026-010401-web-workbench.md) |
| OPS-SENTINEL-REQ-001 | Wrapper边界 | PJ2026-0106050801 Wrapper边界 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[Web工作台](PJ2026-010401-web-workbench.md) |
Web哨兵必须只编排现有顶层 `web-probe observe start/status/command/collect/analyze` 命令语义。常驻服务可以把这些 verb 包成稳定 adapter,但底层采样器、control queue、artifact schema、collect 渲染和 offline analyzer 必须与人工 CLI 共享同一实现或同一生成物。
@@ -485,7 +485,7 @@ Web哨兵必须只编排现有顶层 `web-probe observe start/status/command/col
人工 CLI 是排障和原入口验收的一等入口;哨兵是调度入口。两者对同一 stateDir、同一 report 和同一 trace-frame 的解释必须一致。
`web-probe` 被用于 Workbench smoke 或巡检时,smoke 目标是 Workbench 用户入口,不是 web-probe 自身。若观察到请求风暴、浏览器 freeze、内存上涨、submit/command 失败、trace rows 缺失或 final response 缺失,哨兵只能记录 blocker、root cause、artifact 和 drill-down;修复责任必须回到 [Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md)、[Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md) 或对应业务规格。不得为了让哨兵变绿而减少采样、自动刷新页面、重建 page、关闭 freeze/memory 检测、降低 finding 等级、修改 Playwright 启动参数或把业务 smoke 改成 web-probe 工具自检。
`web-probe` 被用于 Workbench smoke 或巡检时,smoke 目标是 Workbench 用户入口,不是 web-probe 自身。若观察到请求风暴、浏览器 freeze、内存上涨、submit/command 失败、trace rows 缺失或 final response 缺失,哨兵只能记录 blocker、root cause、artifact 和 drill-down;修复责任必须回到 [Workbench实时运行面](PJ2026-0106050514-workbench-realtime-runtime.md)、[Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md) 或对应业务规格。不得为了让哨兵变绿而减少采样、自动刷新页面、重建 page、关闭 freeze/memory 检测、降低 finding 等级、修改 Playwright 启动参数或把业务 smoke 改成 web-probe 工具自检。
### 6.2 OPS-SENTINEL-REQ-002 YAML-first 配置引用
@@ -517,7 +517,7 @@ runner `/health` 必须覆盖配置装载、scheduler/CronJob 观察、artifact
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-SENTINEL-REQ-004 | 报告视图 | PJ2026-0106050804 报告视图 | [Workbench唯一投影](PJ2026-0104010803-workbench-unique-projection.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |
| OPS-SENTINEL-REQ-004 | 报告视图 | PJ2026-0106050804 报告视图 | [Workbench实时权威](PJ2026-010401080313-workbench-realtime-authority.md)、[Workbench性能](PJ2026-01060505-workbench-performance.md) |
Web哨兵的 `sentinel report` 和 dashboard 必须按 YAML report views 渐进展示同一 observe/analyze artifactrun overview、turn-summary、findings、trace-frame/sample drill-down 和显式 raw artifact 下载。默认视图不得 dump JSONL,也不得展示 prompt 原文、完整 assistant 正文、cookie、token、API key、provider payload 或完整 stdout/stderr。