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

Status: implemented

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

## 问题

持久工作流 Chat 节点会在同一位置从运行前缀更新为终态记录。只在挂载时初始化的 disclosure 选择可能隐藏新开始运行的阶段，让已完成工作继续占据对话空间，或者把失败、已取消或已中断成员埋在两层折叠内容之后。若只把开合状态作为完成状态的纯派生结果，虽然能避免这些问题，却也会阻止用户重新打开干净历史进行复盘。

renderer 已经从工作流 Conversation Node 收到全部所需生命周期事实。因此，可见性需要一个组件本地生命周期：让当前执行与需注意状态优先，同时不增加另一项持久事实，也不取得工作流结果的所有权。

## 决策

每个阶段从当前成员派生一项可见性要求。存在运行中、失败、已取消或已中断成员时，该阶段强制展开；全部成员均已完成时，该阶段处于干净状态。工作流自身状态需要注意或任一阶段强制展开时，工作流也强制展开，因此即使工作流结果记录为已完成，异常成员仍保持可见。已完成的兄弟阶段继续可以独立折叠。

强制展开层级渲染为静态展开行。它不提供按钮 role、焦点目标、键盘切换或 `aria-expanded` 值，因为折叠操作无法改变结果。这样既保留视觉层级与状态摘要，也让交互承诺与实际可执行动作一致。

干净层级会以关闭状态挂载普通受控 disclosure。它的本地选择在同一段连续干净状态的 rerender 中保持。新的运行中或异常数据会用强制展开替代该手动区间；下一次回到干净状态时会挂载新的关闭 disclosure，从而让每个活动周期只自动折叠一次。关闭工作流会自然卸载其阶段控件；Session remount 会从当前持久状态重建每个层级，而不恢复更早的选择。

例如，运行中的工作流无需点击即可展示活跃阶段与成员。该阶段完成时，只有阶段折叠，工作流继续展开；工作流自身和全部阶段均完成时，工作流也会折叠。用户随后可以重新打开两个层级复盘。若同一阶段 key 下又开始新成员，受影响的两个层级会立即恢复强制展开，并且只在新活动完成后再次折叠。

renderer 只拥有这项可见性生命周期。它不增加 Session 事件、store、设置、确认状态、计时器、焦点迁移、自动滚动或跨 remount 持久化。它不改变工作流状态派生、阶段分组、成员顺序、导航准入、文案或共享 `DisclosureRow` API。pointer 光标由共享的 `data-expandable` 样式拥有，因此强制展开的静态行不会提示无法执行的操作。持久记录中的中断前缀仍属于需注意状态，因此在底层事实改变前始终可见。

## 验证

组件测试驱动同一个 keyed 工作流与阶段依次经过运行、干净完成、手动复盘、新活动、再次干净完成、零成员完成以及每种异常状态。测试还验证异常成员向上展开、干净兄弟阶段独立、鼠标和键盘复盘、连续干净状态中的选择保持，以及强制展开时不存在虚假按钮和 ARIA 语义。

shipped Web 回放观察真实工作流、worker、Session 日志、浏览器插件图和子级导航。它要求实时工作流与活跃阶段无需 disclosure 控件即可见，正常结算的工作流与阶段会折叠，手动复盘仍能看到不再可导航的终态成员，并且刷新会从持久事实重建折叠历史。

## 曾考虑的替代方案

**保留一项从首次渲染初始化的手动状态。** 拒绝，因为后续生命周期更新无法重新打开新活动或异常内容，也无法折叠正常结算的工作。

**只根据层级是否干净来派生 `open`。** 拒绝，因为已完成历史会永久保持关闭，无法重新打开复盘。

**持久化展开、确认或已读状态。** 拒绝，因为当前生命周期事实已经决定强制可见性，而复盘选择只属于已挂载的展示层。持久化会增加第二个状态归属方，并要求定义陈旧选择、异常确认、回放和同步语义，而用户结果不需要这些机制。

## 后果

工作流记录无需预备点击即可展示当前工作与异常结果，并在正常完成后回收对话空间，同时不牺牲复盘能力。自动控制期间的交互语义保持真实，同一份持久记录在实时渲染、刷新和历史重建时得到相同初始状态。

代价是有意保留的本地重置行为。父工作流关闭或组件卸载时，阶段选择会消失；由于产品没有确认状态，异常记录不能手动隐藏。以后若要支持任一行为，需要单独决定所有权与持久化，而不能隐式扩展这项本地生命周期。
