# Agent Note: 工作流运行的状态驱动 disclosure

Status: implemented

[English](2026-08-11-workflow-run-status-driven-disclosure.md) | 中文

## 问题

持久工作流 Chat 节点会在同一位置从运行前缀更新为终态记录。renderer 必须提示新工作、异常结果和正常完成，同时不能在普通更新中反复覆盖用户回收对话空间的选择。

renderer 已经从工作流 Conversation Node 收到全部持久生命周期事实。因此，disclosure 选择属于已挂载的展示层，但它的生命周期还必须在外层运行隐藏时保留嵌套 Phase 选择，并避免移除仍含键盘焦点的内容。

## 决策

`WorkflowRunPanel` 持有一项运行 disclosure 本地状态，以及一张按现有 phase key 索引的 Phase 状态表。全部成员都已完成时，Phase 为干净状态；任一成员失败、已取消或已中断时为异常状态；其余情况为运行状态。运行自身或任一 Phase 异常时，运行处于异常状态；运行自身或任一 Phase 正在运行时，运行处于运行状态；只有运行与全部 Phase 都正常完成时才处于干净状态。挂载时，运行和异常层级默认展开，干净层级默认折叠。

每个层级记录当前模式、仅追加成员数、开合选择和待执行的干净折叠。Phase 从干净状态进入新活动时，该 Phase 与外层运行自动展开一次；连续运行或异常区间内的普通更新保留用户选择，首次进入异常状态时自动展开一次，进入干净状态时自动折叠一次。若新增成员及其正常完成在同一次渲染中送达，Phase 会保持干净但成员数改变；该变化会折叠已打开的 Phase 复盘，并在运行仍处于活动状态时自动展开外层运行一次，而无需增加 activity epoch 或持久字段。自动动作完成后，鼠标、Enter 和 Space 控制该层级，直到出现下一项约定边沿。

外层 disclosure 隐藏子内容时，Phase 状态仍留在 `WorkflowRunPanel`，因此关闭并重新打开运行会恢复各 Phase 选择。Phase 被移除时，其表项同时清理；renderer remount 会从当前持久事实重建每个层级，而不恢复更早选择。

正常完成会在折叠前检查焦点是否位于内容内。仍含焦点的内容保持挂载并立即显示完成状态，焦点离开后再折叠。可导航成员的按钮持有焦点并变为终态时，`MemberRow` 会把同一个按钮以 `aria-disabled` 形式保留到 blur；之后的终态复盘渲染普通不可交互行。这样既保留当前 DOM 目标，也不允许终态导航，并且无需增加焦点管理器。

renderer 不增加 Session 事件、store、设置、确认状态、计时器、自动滚动、持久活动身份或 `DisclosureRow` API。它不改变工作流状态派生、Phase 分组、成员顺序、导航准入、文案或视觉 token。

## 验证

组件测试驱动同一个 keyed 运行及其 Phase，覆盖初始运行控件、鼠标和键盘选择、普通运行更新、外层隐藏与恢复、Phase 完成、运行完成、干净复盘、同 key 新活动、同次渲染送达的完整干净周期、每种异常状态、首次异常升级、后续异常更新、零成员完成、成员持焦点时完成、兄弟 Phase 独立以及 renderer remount。测试还确认延后焦点路径结算后，终态导航仍不存在。

shipped Web 回放经过真实工作流、worker、Session 日志、浏览器插件图和子级导航。它折叠并重新打开实时运行与 Phase 控件，记录实时折叠标题的状态摘要和 ARIA 状态，验证正常结算会折叠两个层级，确认终态复盘不能导航成员，并记录刷新后从历史重建的折叠记录。

## 曾考虑的替代方案

**把每个运行中或异常层级强制展开为静态行。** 拒绝，因为需注意状态将无法收起，也不会提供真实的鼠标、键盘和 ARIA disclosure 语义。

**保留一项从首次渲染初始化的手动状态。** 拒绝，因为后续活动、异常升级和正常完成无法执行各自的一次性自动动作。

**让每个 Phase 在自身 disclosure 内容中持有状态。** 拒绝，因为隐藏外层运行会卸载这些内容，并在同一条已挂载工作流记录中丢失独立的 Phase 选择。

**持久化展开、确认或 activity epoch。** 拒绝，因为当前工作流事实与仅追加成员数已经提供全部所需边沿。持久化会增加第二个持久归属方以及本展示选择不需要的同步语义。

## 后果

工作流记录会提示生命周期变化，同时在所有状态下都允许用户收起。正常完成会回收空间，当前焦点保持安全，嵌套 Phase 选择在外层隐藏期间保留；同一份持久记录在刷新或历史回放时会重建确定性的初始状态。

这项本地生命周期会在 renderer remount 时重置，无法跨刷新、设备或用户记住选择。若要增加该行为，需要单独决定持久化与陈旧选择语义，而不能隐式扩展这项展示状态。
