Transitions
A role’s form_schema can declare at its root that submitting one of its escalations pauses on a wait screen instead of returning to the list, because a follow-on escalation is about to be handed to the same person. The result feels like a multi-page form: submit, a brief “one moment”, then the next step opens.
| Token | Type | Meaning |
|---|---|---|
x-lt-transition |
boolean |
Show the wait screen after a successful resolve |
x-lt-transition-message |
markdown | Shown on the wait screen. Defaults to “Submitted. Preparing your next step…” |
x-lt-transition-max-wait-seconds |
number |
How long to wait for the follow-on before the fallback runs. Clamped to 5 to 300; defaults to 30 |
x-lt-transition-done |
href template | Where to go when the step ends without a further hand-off. Independent of x-lt-transition |
{ "type": "object", "x-lt-transition": true, "x-lt-transition-message": "**Account saved.**\n\nSetting up your preferences…", "x-lt-transition-max-wait-seconds": 20, "properties": { /* … */ }}These tokens control the experience only. The schema never names the next escalation.
How navigation happens
Section titled “How navigation happens”The workflow creates the follow-on born assigned to the submitter in one atomic commit:
const step1 = await conditional<Step1 & { $resolution?: EscalationResolution }>(sig1, { role: STEP1_ROLE, /* … */ schemaVersion: 1,});const owner = step1.$resolution?.resolvedBy; // who resolved step 1const parent = step1.$resolution?.escalationId; // step 1's id, the correlation key
await conditional<Step2>(sig2, { role: STEP2_ROLE, assignee: owner, // born assigned durationMinutes: 30, // a hard claim keeps it with the owner parentId: parent, // the escalation the owner is on when they submit schemaVersion: 1,});The engine emits a claimed event for the born-assigned row carrying, in one statement:
data.assigned_to: who it went to.data.parent_id: the escalation it descends from.assigned_at_creation: true: a directed, system-issued assignment.
The dashboard navigates only when all three match the viewer and the page: assigned_to is the viewer, parent_id is the escalation on screen, and assigned_at_creation is true. An unrelated assignment, or a claim the viewer made, leaves the page where it is.
durationMinutes matters. An assignee with no window is a soft routing hint that others may still claim, so a directed hand-off arms a claim window to keep the follow-on with its owner.
Where a step lands: x-lt-transition-done
Section titled “Where a step lands: x-lt-transition-done”A step reached by a forward transition has no meaningful “back”. A terminal step (or any form) declares where to go on submit:
{ "x-lt-transition-done": "/escalations/available?role=onboarding-step-1" }The value is an href template with the same {{domain.path}} interpolation and routing rules as x-lt-href: an internal path navigates in the dashboard, anything else opens externally. It can be a plain page or a faceted worklist URL (facets, role, assignment), for example the queue of items still waiting. It runs in the browser only.
On submit the page resolves in order: x-lt-transition (wait for the hand-off), then x-lt-transition-done (go to the declared destination), then history.back(). On a transition step, x-lt-transition-done is also where the wait lands if the follow-on never arrives.
Station recipe: submit lands on the list. Shared-station flows (badge scan, claim, resolve) reach the detail page from angles where browser history means little. Declare the destination on the role’s form-schema root and every submit returns to the role’s queue:
{ "x-lt-transition-done": "/escalations/available?role={{escalation.role}}&status=available" }With no follow-on to wait for, leave x-lt-transition off; the navigation is immediate.
If the live event is missed
Section titled “If the live event is missed”Event delivery is at-most-once: a crash between the commit and the publish drops the event. When the wait exceeds x-lt-transition-max-wait-seconds, the page runs a precise fallback query (the child of this escalation assigned to the viewer, by parent_id and assigned_to) and lands on it if present. Otherwise it goes to the x-lt-transition-done destination or the list.
Reference example
Section titled “Reference example”The transition-chain example workflow is a three-step onboarding wizard: step 1 is open to the pool, and steps 2 and 3 are born assigned to the owner. Steps 1 and 2 opt into the hand-off; step 3 is terminal.
