HilPresentationReplyEnvelope

Browser → Server  ·  Version 1.3  ·  Phase 2 (Resumption)

Structure

HilPresentationReplyEnvelope ├── EngageSessionID int — echoed from request session ├── CorrelationID string — echoed from Session.CorrelationID ├── ReplyToID string? — echoed from Session.ReplyToID │ ├── Responders[] { ActorID, ActorType, DisplayName, ResponderRole } │ ├── Decision "approved" | "rejected" | "submitted" | "replied" | ... ├── ActionName "approveOrder" | "cancelOrder" | "submitForReview" | ... ├── DecidedAt ISO 8601 UTC ├── Channel "web" | "slack" | "email" | "mobile" | "api" │ ├── Actions[] audit trail │ └── { ActionType, ActionName, ActionLabel, PerformedBy, PerformedAt, ActionData{} } │ ├── Payload │ ├── DataSteps[] per-step (EnableSteppedDataReturn=true, default) │ │ └── { StepOrder, PresentationType, ActionName, Data{}, CompletedAt } │ ├── Data{} merged flat bag (EnableFlatDataReturn=true, default) │ ├── ReplyText? chat typed field │ ├── ThreadID? │ ├── Comment? approval typed field │ ├── Reason? rejection / escalation reason │ └── Raw? JsonElement fallback └── Metadata{}

Decision vs ActionName

Decision = standard routing token (node selects output port). ActionName = domain-specific button key echoed from Actions[].ActionKey in the request. They may be identical ("approved") or differ (ActionKey:"approveOrder" → Decision "approved").
FieldPurposeExamples
DecisionStandard routing token — node executor selects output portapproved, rejected, submitted, replied
ActionNameDomain-specific named action — business context, echoed from requestapproveOrder, cancelOrder, submitForReview, requestRevision

Payload — DataSteps vs Data

FieldControlled byDefaultBest for
DataSteps[]EnableSteppedDataReturntrueMulti-step flows, full traceability — which data came from which step and which action triggered it
Data{}EnableFlatDataReturntrueSingle-step flows, legacy consumers expecting a simple flat key-value bag
ReplyTextAlways populatedChat interactions — typed convenience, no parsing needed
CommentAlways populatedApproval decisions with notes
ReasonAlways populatedRejections and escalations with structured reason

HilReplyStep — ActionName binding

DataSteps[N].ActionName ties the named action directly to the data submitted at that step. Example: step 2 completed via "submitForReview"{ StepOrder:2, ActionName:"submitForReview", Data:{Rating:"4",...} }. The server knows both what was entered and what the actor intended.
StepOrderintMatches HilPresentation.Order from the request.
PresentationTypestringMirrors the request's PresentationType: "form", "chat", "approval", "info".
ActionNamestringNamed action that completed this step. Empty for intermediate navigations (e.g., “next” between steps).
Data{}DictionaryKey-value data for this step. Form: field→value. Chat: ReplyText→string. Approval: Comment→string. Info: empty.
CompletedAtstringISO 8601 UTC timestamp when this step was completed.

Responder Roles

ResponderRoleMeaning
primaryThe main actor who performed the interaction (default, 99% of cases)
delegateActing on behalf of the assignee
co-signerRequired co-approver
witnessObserved the interaction for audit purposes

Standard Decisions

DecisionUsed byActionType (audit)
approvedApproval, Chatapprove
rejectedApproval, Chatreject
submittedForm, FormTriggersubmit
repliedChat, ChatTrigger, ChatReceivereply
escalatedApprovalescalate
cancelledAllcancel
abstainedApprovalabstain

C# Model

C#
public class HilPresentationReplyEnvelope
{
    public int                                    EngageSessionID { get; set; }
    public string                                  CorrelationID   { get; set; } = string.Empty;
    public string?                                 ReplyToID       { get; set; }
    public List<HilPresentationReplyResponder>    Responders      { get; set; } = new();
    public string                                  Decision        { get; set; } = string.Empty;
    public string                                  ActionName      { get; set; } = string.Empty;
    public string                                  DecidedAt       { get; set; } = string.Empty;
    public string                                  Channel         { get; set; } = string.Empty;
    public List<HilPresentationReplyAction>       Actions         { get; set; } = new();
    public HilPresentationReplyPayload            Payload         { get; set; } = new();
    public Dictionary<string, object>            Metadata        { get; set; } = new();
}

public class HilPresentationReplyPayload
{
    public List<HilReplyStep>           DataSteps { get; set; } = new();
    public Dictionary<string, object> Data      { get; set; } = new();
    public string?                      ReplyText { get; set; }
    public string?                      ThreadID  { get; set; }
    public string?                      Comment   { get; set; }
    public string?                      Reason    { get; set; }
    public JsonElement?                Raw       { get; set; }
}

public class HilReplyStep
{
    public int    StepOrder        { get; set; }
    public string PresentationType { get; set; } = string.Empty;
    public string ActionName       { get; set; } = string.Empty;
    public Dictionary<string, object> Data { get; set; } = new();
    public string CompletedAt      { get; set; } = string.Empty;
}

public class HilPresentationReplyResponder
{
    public string  ActorID       { get; set; } = string.Empty;
    public string  ActorType     { get; set; } = "user";
    public string? DisplayName   { get; set; }
    public string  ResponderRole { get; set; } = "primary";
}