You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(console): make a paused screen flow completable, and stop the runner from tearing down its host (framework#3528) (#2830)
Two defects on the screen-flow path, both ending in "Submit never resumes".
**Flow Runs test runner had no second half.** Developer → Flow Runs triggers a
flow and renders the result. For a screen flow that result is not a result — it
is `{ status: 'paused', runId, screen }`, and the run sits suspended until
something posts to its resume endpoint. The panel dumped the envelope as JSON
and stopped: no screen, no Submit, no resume call, and an orphaned `paused` row
in Recent Runs for every test run. It now hands the pause to the same
`FlowRunner` the record and list surfaces use, so the screen renders for real
(flat fields, multi-step wizards, and `object-form` steps with their
master-detail grids). Dismissing the runner no longer strands the run: the
suspension is durable, so a "Continue run" affordance reopens the pending
screen. `paused` also gets its own status badge instead of falling through to
the unknown-status style.
**FlowRunner tore down its host.** An `object-form` step mounts ObjectForm,
whose field widgets are lazy. That suspension unwound to the *host's* nearest
`<Suspense>`; where that is the route-level boundary, React swapped the whole
page for the fallback and remounted it, destroying the host's state and this
dialog with it. The screen vanished before it could be filled in and the run
stayed paused with no resume call — the reported symptom exactly. The runner
now owns a boundary around its screen body, so the lazy load is local and no
host can be torn down by it. Verified in a browser against a live server: the
two-step Convert Lead wizard now creates the account, resumes, and renders
step 2.
Also: a screen payload without `fields` no longer throws. `fields` is optional
on the wire (a message-only screen, or an executor that omits it) but was read
unguarded as the dialog mounted; reads go through a `screenFields()` helper and
the design-time builder keeps its exhaustive shape. `FlowRunner` and its types
are exported from the package so surfaces outside `views/` can mount the one
runner instead of reimplementing it.
Claude-Session: https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5
Co-authored-by: Claude <zhuangjianguo@steedos.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
0 commit comments