Repository navigation
Description
Part of the Screenplay command production model: Cratis/Screenplay#309.
Why
A command can return a value to its caller, such as the id of the project it just created (Cratis/Screenplay#300, Cratis/Screenplay#303, decision 0021). A screen should be able to use it: submit the form, then navigate to the new item. Scene can't express that today:
Formhas noOnSubmit(Source/DotNET/Model/Forms/Form.cs:15), so the form's continuation is lost.- Nothing binds the response.
CommandOutcome.response?: unknownexists (Source/JavaScript/engine/ActionDispatcher.ts:12-17), but the engine binds nothing from it.
Example
Screenplay input:
command RegisterProject
projectId ProjectId generated identifier
slug ProjectSlug generated
name ProjectName
produces event ProjectRegistered
name ProjectName = name
returns
projectId = projectId
slug = slug
form RegisterProjectForm for RegisterProject
field name
on submit navigate to ProjectDetails by projectId
on submit means "execute the form's command, and on success run these actions". projectId is a returned name.
Scene contract, sketch of the change (the JSON shape and the binding path prefix are not decided; see open decisions):
{
"name": "RegisterProjectForm",
"forCommand": "RegisterProject",
"fields": [{ "name": "name" }],
"onSubmit": [ // new: same actions as an interaction's continuation
{
"kind": "navigate",
"screen": "ProjectDetails",
"arguments": [
{ "name": "projectId", "value": { "path": "commandResponse.projectId" } } // new binding source
]
}
]
}C# model sketch:
public record Form(string Name, string ForCommand, PopulateSource? PopulateSource, IReadOnlyList<FormField> Fields)
{
public IReadOnlyList<Behavior> Behaviors { get; init; } = [];
public IReadOnlyList<InteractionAction> OnSubmit { get; init; } = []; // new
}Engine sketch: after executeCommand returns a CommandOutcome with isSuccess: true, resolve a commandResponse.<field> argument from outcome.response and hand the action to the dispatcher.
Scope / acceptance criteria
- Forms: add
OnSubmittoFormwith the same continuation actions as interactions, such as navigate and open. Serialization and the TypeScript model follow. - Response binding: add a
commandResponsebinding source, so a continuation can use the whole response, or a field of it, as an argument.- Applies to
on submitand toExecuteCommandAction.OnSuccess. - The engine reads it from
CommandOutcome.response.
- Applies to
- Failure rule: a failed command has no response. Continuations under
on failurecan't bind it. Model validation rejects it; the engine never resolves it at runtime. - A missing field in the response (a command with no
returns) is a model error, not a runtimeundefined. - Specs: form submit navigation; response binding to a single field; whole-response binding; rejection of a binding under failure.
Open decisions
- Binding representation.
BindingExpressionis a resolved path string. Does the response binding become a path prefix (commandResponse.projectId), or a new binding record that says which command's response it reads? - Response shape. A single returned value (Generated command values and returning a value to the caller Screenplay#300) is a scalar, not an object. Does
commandResponsebind the scalar directly, and fields only for thereturnsblock (Idea: returning several values from a command (returns block) Screenplay#303)? - Meaning of
on submit. Is it success-only, or does it also cover failure paths? The current proposal is success-only, withon failureunchanged. - Typing. Does Scene carry a type for the response so a renderer can check the binding, or does it trust the producer (Stage translating Screenplay), as it does for other resolved paths?
Related
- Generated command values and returning a value to the caller Screenplay#300, Idea: returning several values from a command (returns block) Screenplay#303, Idea: command production model — overview, principles and open decisions Screenplay#309
- Render generated values and command responses through to the frontend Stage#175 (
FormConverterandInteractionActionConverterconsume this) - Proxy generator: do not type Chronicle events as the command response Arc#2885
Status
State: Done — Shipped in Scene v4.84.0 (PR #273, merge fa5936d).
Branch: studio-856-auto-merge (#273)
Scope: Form onSubmit continuations bound to the command response (accepted L32 design).
Plan: Additive Form.OnSubmit and a commandResponse binding source. A producer-supplied response contract drives recursive fail-closed validation with C#/TS parity. The engine runs the continuation once, only after native Arc success, with a lexical response scope.
Delivered: Nothing yet.
Remaining: To be confirmed.
Follow-ups: None.
Activity
github-actions commentedon Oct 26, 2026
Closed by release v4.84.0.