Expand description
Production SessionResumer that resumes a paused flow by feeding a
synthesized IngressEnvelope back through the runtime ingress entry
(StateMachineRuntime::handle).
§How a resume is keyed (verified against engine/runtime.rs)
When a sorla.call await node pauses, PackFlowAdapter::call persists the
wait via FlowResumeStore::save(envelope, wait). The wait is keyed by
build_store_ctx, which derives:
- a store hint =
session_hint(elsecanonical_session_hint), and whenpack_idis present, suffixed with::pack=<pack_id>; - a user id =
sha256(store_hint)(seederive_user_id); - a reply scope = the envelope’s
ReplyScope(whosescope_hashcoversconversation/thread/reply_to).
To resume, FlowResumeStore::fetch(envelope) re-derives the same triplet,
so the synthesized envelope MUST reproduce the exact store hint and reply
scope used at save time. The dispatch correlation id echoed in the response
is ctx.session_id — the canonical session hint (optionally carrying the
::pack=<id> suffix). This resumer splits that suffix off, sets the BARE
hint as session_hint (so build_store_ctx re-appends the pack suffix
exactly once), carries the recovered pack_id, and rebuilds the reply scope
by parsing the conversation out of the canonical hint
(tenant:provider:channel:conversation:user).
§Keying + routing caveat (IMPORTANT — see PR notes)
Resuming through handle requires the synthesized envelope to (a) ROUTE via
StateMachine::step, which needs a registered (pack_id, flow_id), and
(b) KEY the saved wait via FlowResumeStore::fetch, which needs the store
hint (<bare hint>::pack=<pack_id>) and the reply scope (scope_hash over
conversation/thread/reply_to).
The dispatch wire contract (greentic_types::RuntimeDispatchResponse plus
the Greentic-* headers) carries only (tenant, env, correlation_id). The
correlation id is the canonical session hint, which embeds the conversation
(4th :-segment) but NOT the pack_id or flow_id needed to route.
This resumer recovers pack_id from a ::pack=<id> suffix (the convention
pinned by tests/sorla_node.rs, where ctx.session_id carries it) and
flow_id from an additional ::flow=<id> marker. For production resume to
work, the dispatch side must therefore emit a correlation id of the form
<bare hint>::pack=<pack_id>::flow=<flow_id> (or the wire contract must be
extended to carry pack/flow, or a server-side correlation_id → (pack, flow, scope) map must exist). A bare canonical hint alone is NOT resumable.
Waits whose original inbound used a non-empty thread/reply_to ARE
resumable: execute_sorla_call appends ::thread=<t>/::reply=<r> markers
(each omitted when empty), and this resumer strips them and feeds them back
into the synthesized ReplyScope so fetch recomputes the same
scope_hash save used. The no-thread case is unchanged (no markers
emitted → thread/reply_to stay None).
Structs§
- Runtime
Session Resumer - Resumes paused flow sessions by driving the runtime ingress entry.