fix(workbench): converge projection signal and detail read terminology

This commit is contained in:
root
2026-07-09 06:05:42 +02:00
parent 838224211b
commit ac412b557c
15 changed files with 178 additions and 140 deletions
+6 -6
View File
@@ -15,13 +15,13 @@
Workbench 页面和组件必须明确区分“未加载完成”和“已加载但为空”。未加载完成时不得渲染由 workspace、localStorage、默认对象或 stub 记录拼出来的伪数据;这类数据只能作为内部恢复线索,不能在列表、表格、卡片或状态栏中冒充真实加载结果。已经确认后端返回且集合为空时,才显示空态文案。
Workbench 状态对象必须服从 UniDesk OA Web SPEC 中已经定下来的单一权威 API 绑定。Session rail 的会话集合只允许消费 `/v1/agent/conversations` 成功返回的 conversation 集合;当前 selected conversation 如果需要出现在左侧列表中,必须通过显式 query/path/body 传入稳定 conversation id,由该列表 API 在同一响应中返回,后端不得隐藏读取 workspace selected、localStorage、Web snapshot 或上一轮页面状态。前端不得用 workspace selected snapshot、stub、localStorage 或 route 状态补出 session tab,也不得把前端拼接出的 status、final response、markdown、running 动效或 stub 传回后端变成事实。Session 运行状态必须按 `sessionId` 绑定到单一 session 状态 APICode Agent turn、trace 阅读和 final response 必须按 `traceId` 绑定到单一 trace/result snapshot API。任何权威 API 失败时只能保留上一份成功结果或显示未加载/错误态,不得切换到另一条 fallback 路径形成一条会话、旧 running 态或劣化 markdown。
Workbench 状态对象必须服从 UniDesk OA Web SPEC 中已经定下来的单一权威 API 绑定。Session rail 的会话集合只允许消费 `/v1/workbench/sessions` 成功返回的 Workbench session read model;当前 selected conversation 如果需要出现在左侧列表中,必须通过显式 query/path/body 传入稳定 conversation id,由该列表 API 在同一响应中返回,后端不得隐藏读取 workspace selected、localStorage、Web snapshot 或上一轮页面状态。前端不得用 workspace selected snapshot、stub、localStorage 或 route 状态补出 session tab,也不得把前端拼接出的 status、final response、markdown、running 动效或 stub 传回后端变成事实。Session 运行状态turn 投影、trace 终态和 final response 的自动恢复必须以 Workbench read model 和 `/v1/workbench/sync` replay 为权威;`/v1/workbench/turns/:traceId``/v1/workbench/traces/:traceId/events` 与旧 `/v1/agent/*` detail 入口只能服务显式详情、历史查看或兼容调用,不能成为 Workbench 自动投影的第二条事实来源。任何权威 API 失败时只能保留上一份成功结果或显示未加载/错误态,不得切换到另一条 fallback 路径形成一条会话、旧 running 态或劣化 markdown。
Workbench 投影写路径必须做到 0 隐式 fallback。Admission、projection event、terminal/finalizer 等上游写入如果无法把 session/message/turn/checkpoint facts 写入 durable read model,不能 `catch` 后返回空值继续表现为成功;admission 阶段必须显式失败并把错误传给调用方,后台投影阶段必须至少写入 trace diagnostic 和 OTel error span。只有成功落库的 Workbench facts 才能驱动控制页、观察页、session rail、耗时和 final response;前端或 read path 不得用内存 trace、local optimistic state、历史 snapshot 或多来源仲裁去修补失败写入。
Workbench 的 trace/message/projection 运行时必须是独立模块边界。`workbench.ts` 只保留 session/route authority 校验、Pinia state commit、刷新调度和用户动作编排;trace snapshot、terminal result、message timing/status patch、agent error normalize、projection diagnostic 裁剪和 final response 文本提取等纯算法统一由 `web/hwlab-cloud-web/src/stores/workbench-message-projection-runtime.ts` 提供。新增或修复浏览器 smoke 时不得把这些 helper 重新散写回 store 或组件,也不得通过 reload、repair、localStorage truth、GET read-through、测试专用后门或删除 guard 来绕过真实投影问题。web-probe origin、视口、采样、命令超时、provider/lane 和报警阈值只从选中 node/lane 的受控 YAML/source-of-truth 进入验证命令,不在 SPEC 或前端 runtime 中写第二份数值。
Workbench terminal 三态必须作为一个不可拆分的投影不变量维护:session rail 状态、turn 卡片状态和 final response object 要么同时表现为完成且 final response 存在,要么同时表现为运行且 final response 不存在。持久 read model 是 session、messages、turn、trace tuple 的 source of truth;前端 `workbench-server-state` 只能做归一化缓存和单调合并,不能把 stale running 刷新覆盖到同一 trace 的 terminal authority 上。`session.status``turn.status``session.list/detail/messages``message.snapshot`、projection page merge、REST trace hydration 和 SSE trace snapshot 都必须保留已 sealed terminal 的 `status``traceAutoLifecycle``text``finalResponse` 和 terminal timing;新 trace 的 running 可以让同一 session 进入下一轮运行,但同 trace 的 running/non-terminal 只能作为旧事件丢弃或合并为 runnerTrace 证据。判断 final response 是否存在时必须能从 `text``content``finalResponse``reply/finalText` 等权威字段提取非空文本,空对象、进度 assistant trace 文本或仅有 AgentRun completed 状态都不能 seal completed`/v1/agent/turns/:traceId`、Workbench read model、projection writer、runtime store invariant 和前端缓存层必须共用这个 terminal seal gate。新增修复应优先补 `workbench-message-projection-runtime``workbench-server-state` 或对应后端 read-model 的最小单元测试,而不是用 UI 特判、reload 或额外 fallback 掩盖投影分叉。
Workbench terminal 三态必须作为一个不可拆分的投影不变量维护:session rail 状态、turn 卡片状态和 final response object 要么同时表现为完成且 final response 存在,要么同时表现为运行且 final response 不存在。持久 read model 是 session、messages、turn、trace tuple 的 source of truth;前端 `workbench-server-state` 只能做归一化缓存和单调合并,不能把 stale running 刷新覆盖到同一 trace 的 terminal authority 上。`session.status``turn.status``session.list/detail/messages``message.snapshot`、projection page merge、detail/history trace reads 和 SSE trace snapshot 都必须保留已 sealed terminal 的 `status``traceAutoLifecycle``text``finalResponse` 和 terminal timing;新 trace 的 running 可以让同一 session 进入下一轮运行,但同 trace 的 running/non-terminal 只能作为旧事件丢弃或合并为 runnerTrace 证据。判断 final response 是否存在时必须能从 `text``content``finalResponse``reply/finalText` 等权威字段提取非空文本,空对象、进度 assistant trace 文本或仅有 AgentRun completed 状态都不能 seal completedWorkbench read model、`/v1/workbench/sync` replay、projection writer、runtime store invariant、显式 turn/detail API 和前端缓存层必须共用这个 terminal seal gate。新增修复应优先补 `workbench-message-projection-runtime``workbench-server-state` 或对应后端 read-model 的最小单元测试,而不是用 UI 特判、reload 或额外 fallback 掩盖投影分叉。
MDTODO 发起 Workbench 执行时,HWPOD 执行上下文的唯一权威来源是 Project Management source registry。Workbench Launch 服务端必须通过 `taskRef -> sourceId/fileRef -> source` 解析 `launchContext.executionContext`,并把同一份 `contextFingerprint` 写入 session owner、Workbench facts、project-management link 和 OTel span;浏览器传入的 HWPOD 字段只能作为任务元数据,不能作为权威执行上下文。`sourceKind=hwpod-workspace` 但缺少 `hwpodId``nodeId``workspaceRootRef` 时,launch 必须显式失败,不能创建“看似成功但无法执行”的空 session。
@@ -29,15 +29,15 @@ MDTODO 首轮 Code Agent prompt 必须包含 `hwpodId`、`mdtodoRootRef` 和 `hw
Cloud Web 的通用加载态使用 `web/hwlab-cloud-web/src/components/common/LoadingState.vue`。新增或修复页面加载态时优先复用该组件,并通过明确的 ready/loading 状态控制展示;不要在每个组件里重新实现一套 spinner、点状动画或默认占位数据。紧凑区域可以使用组件的 compact 形态,文案默认保持“加载中”。
Session rail 是该规则的高频区域。`/v1/agent/conversations` 还未返回时,即使 workspace 中已有 `selectedConversationId`、sessionId、traceId 或 selected conversation snapshot,也不能把选中 session stub 渲染成单条 `.session-tab`,更不能让它占满整个 session 列表高度。加载窗口应只显示 `LoadingState`,并隐藏当前 trace 元信息、复制/删除等依赖真实 active tab 的动作;待 conversations ready 后再渲染真实 session tabs,或在真实空集合时显示空态。
Session rail 是该规则的高频区域。`/v1/workbench/sessions` 还未返回时,即使 workspace 中已有 `selectedConversationId`、sessionId、traceId 或 selected conversation snapshot,也不能把选中 session stub 渲染成单条 `.session-tab`,更不能让它占满整个 session 列表高度。加载窗口应只显示 `LoadingState`,并隐藏当前 trace 元信息、复制/删除等依赖真实 active tab 的动作;待 Workbench session list ready 后再渲染真实 session tabs,或在真实空集合时显示空态。
Session rail 的后台恢复刷新必须有硬边界。显式用户动作或强一致操作(例如选择会话、删除当前会话)可以立即刷新会话列表;SSE error、active trace sync replay、terminal refresh、trace hydration 等后台补偿路径不得绕过 session list 的冷却/合并机制去强制刷新完整列表。后台路径应优先补当前 trace、turn status、message projection 和必要的 trace events;需要刷新 session rail 时走统一的 scheduled refresh,并按 session/list key 合并已有 timer,避免网络抖动或 EventSource error storm 把 `/v1/workbench/sessions` 放大成浏览器内存和 CDP responsiveness 红灯。
Session rail 的后台恢复刷新必须有硬边界。显式用户动作或强一致操作(例如选择会话、删除当前会话)可以立即刷新会话列表;SSE error、active trace sync replay、terminal refresh、detail/history trace reads 等后台补偿路径不得绕过 session list 的冷却/合并机制去强制刷新完整列表。后台路径应优先补当前 trace、turn status、message projection 和必要的 trace events;需要刷新 session rail 时走统一的 scheduled refresh,并按 session/list key 合并已有 timer,避免网络抖动或 EventSource error storm 把 `/v1/workbench/sessions` 放大成浏览器内存和 CDP responsiveness 红灯。
Workbench realtime 恢复与 sync replay 必须统一接入已经迁移的 OpenCode-style runtime 模块。`workbench-stream-transport` 只拥有 SSE lifecycle、cursor 和 recovery reason`workbench-realtime-plan` 只把 transport action 转成纯 plan`workbench-refresh-runtime`、keyed singleflight、scheduled task runtime、trace hydration queue、server-state reducer 和 session cache 是恢复读取的唯一 substrate。`workbench.ts` 不得再持有新的 in-flight map、timer map、cursor map、REST recovery queue 或第二套 recovery coordinator。`force` 是用户显式操作和恢复优先级语义,不得绕过同 key 的 singleflight、cooldown、min interval 或 storm budget;这些预算、退避、并发、页数、重试和窗口参数只由 node/lane YAML-backed runtime policy 注入,SPEC 只声明字段族、责任边界和验收读取方式,不写死数值。
Workbench realtime 恢复与 sync replay 必须统一接入已经迁移的 OpenCode-style runtime 模块。`workbench-stream-transport` 只拥有 SSE lifecycle、cursor 和 recovery reason`workbench-realtime-plan` 只把 transport action 转成纯 plan`workbench-refresh-runtime`、keyed singleflight、scheduled task runtime、trace history queue、server-state reducer 和 session cache 是恢复读取的唯一 substrate。`workbench.ts` 不得再持有新的 in-flight map、timer map、cursor map、detail-read recovery queue 或第二套 recovery coordinator。`force` 是用户显式操作和恢复优先级语义,不得绕过同 key 的 singleflight、cooldown、min interval 或 storm budget;这些预算、退避、并发、页数、重试和窗口参数只由 node/lane YAML-backed runtime policy 注入,SPEC 只声明字段族、责任边界和验收读取方式,不写死数值。
Workbench Realtime Authority v2 的自动恢复只允许消费 SSE typed event 和 `/v1/workbench/sync` replay。`/workbench/sync` 返回的 durable `delta.messages``delta.turns` 等 family object 必须在前端 authority 层投影成带 `realtimeAuthority`、entity family/id/version 和 projection revision 的 `message.snapshot``turn.snapshot` 等 typed event,再进入统一 reducer;不得把 family delta 当成不可应用的普通对象,也不得用 `/v1/workbench/sessions/:id/messages``/v1/workbench/turns/:id``/v1/workbench/traces/:id/events` 自动 fan-out 补洞。跨 tab/page 的 `session-projection` signal 只能触发同一 `/workbench/sync` replay 或临时 optimistic echo,最终必须由 durable sync delta 覆盖并让 control/observer 页在同一个 session 上收敛到相同 messages/turn projection。`workbench-server-state``message.snapshot` guard 只能拒绝无 messageId、无 trace 或当前会话没有同 trace 上下文的孤儿 agent snapshotdurable user fact 之后到达的同 trace agent snapshot 必须可追加。新增修复应覆盖“observer 从空消息状态应用 sync replay 后得到 user/agent messages 与 turn status”的最小测试,并用 web-probe `observe analyze` 确认没有 persistent `cross-page-projection-divergence` 或 automatic recovery legacy fan-out 红项。
Workbench 只能维护一条会话恢复与提交路径。首次打开、新建后继续、从左侧 session rail 切换、直接进入 `/workbench/sessions/<conversationId>` 恢复时,都必须以当前 route/active conversation id 作为会话真相,并通过同一条 conversation detail hydration 路径得到 messages、turn state、trace/status 和 markdown 渲染输入;不得另写只消费列表 snapshot、workspace stub 或 localStorage selected id 的恢复分支。
Workbench 只能维护一条会话恢复与提交路径。首次打开、新建后继续、从左侧 session rail 切换、直接进入 `/workbench/sessions/<conversationId>` 恢复时,都必须以当前 route/active conversation id 作为会话真相,并通过同一条 conversation detail read 路径得到 messages、turn state、trace/status 和 markdown 渲染输入;不得另写只消费列表 snapshot、workspace stub 或 localStorage selected id 的恢复分支。
Workbench 的 URL 反射必须服从用户当前导航和组件生命周期。`activeConversationId`、hydrate、select conversation 或列表刷新等异步状态只能在当前 route 仍属于 Workbench section、路径仍是 `/workbench`/`/workspace` 系列且 Workbench 组件仍 active 时,才允许把 URL 反射到 `/workbench/sessions/<conversationId>`;用户已经点击 Dashboard、API Keys、Admin、Settings 或其他非 Workbench 导航后,晚到的 Workbench 响应只能更新 store,不得再调用 `router.replace`/`router.push` 把全局 route 拉回 Workbench。新增 session 恢复或 URL 反射入口时必须复用共享路由守卫,例如 `web/hwlab-cloud-web/src/router/workbench-navigation.ts`,不要在业务组件里各自手写跳转判断。