Skip to content

screen flows: resume performs no server-side validation — missing required fields and undeclared keys all complete the run #4477

Description

@baozhoutao

Found while verifying the 17.0.0-rc.1 checklist on #3909 (section C — "Screen flows (#3528): … visibleWhen honored in render+validation"). Verified on main @ 1ee48bc60 with a purpose-built two-field screen flow.

The render half works. There is no validation half — POST …/runs/:runId/resume accepts anything.

Specimen

{ id: 'ask', type: 'screen', label: 'Triage', config: { fields: [
    { name: 'kind', label: 'Kind', type: 'text', required: true },
    { name: 'escalation_reason', label: 'Escalation reason', type: 'text',
      required: true, visibleWhen: "kind == 'escalate'" },
]}}

Render — correct

The trigger response and GET …/runs/:runId/screen both carry the predicate intact, so a renderer has what it needs:

{"nodeId":"ask","title":"Triage","fields":[
  {"name":"kind","label":"Kind","type":"text","required":true},
  {"name":"escalation_reason","label":"Escalation reason","type":"text",
   "required":true,"visibleWhen":"kind == 'escalate'"}]}

Resume — accepts every shape

resumed with expected actual
{"kind":"normal"} — conditional field hidden accept 200 accept
{"kind":"escalate"} — conditional field VISIBLE and required, value missing reject 200 accept
{}kind itself required, unconditional, missing reject 200 accept
{"kind":"normal","totally_bogus":"x"} — undeclared key reject 200 accept

Every one completes the run (success: true, both nodes status: "success").

So the checklist's "honored in validation" reads as passing only vacuously: nothing is validated, so the conditional-required case cannot be got wrong. A client that skips the dialog and posts to resume directly bypasses every required the flow author declared.

Why this matters here specifically

Screen flows are the one place where the declared field contract is the only contract — there is no object schema behind a screen node to catch it downstream. The platform enforces the analogous contracts everywhere else this train touched: action params are strict by default with required/option/unknown-key checks (ADR-0104 D2, #4213 — verified working), record writes enforce required with per-field errors (ADR-0113, #4031 — verified), approval decisionOutputs reject a missing required key and an undeclared one (#3447 — verified, with the declared keys listed in the error). Screen-flow resume is the gap in that row.

Expected

resume validates the submitted bag against the suspended node's declared fields, evaluating visibleWhen against the submitted values first: a hidden field's required does not fire, a visible one's does, and an undeclared key is refused — the same shape enforceActionParams already produces (Invalid action params: …, 400).

Part of the #3909 rc.0/rc.1 verification (section C).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions