Skip to content

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.

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 1
const 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.

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.

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.

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.