Skip to content

feat(core): rework form when conditions#35115

Merged
rekram1-node merged 2 commits into
v2from
form-when
Jul 3, 2026
Merged

feat(core): rework form when conditions#35115
rekram1-node merged 2 commits into
v2from
form-when

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #35108. Reworks the form when conditional-visibility contract, which was previously under-specified and partly broken (a when targeting a boolean or number field could never match because value was string-only and compared with ===).

Schema (Form.When)

  • when is now always an array (When[]), evaluated as AND.
  • value is string | number | boolean, matching the referenced field's type.
  • Ops stay minimal: eq / neq. Extensions (in, etc.) can be added later without breaking the shape.

Semantics (documented on the schema and enforced in core)

  • Against a multiselect answer, eq means "selection includes value", neq means "does not include".
  • An unanswered referenced field makes the condition false for both ops (kills the old accident where neq activated fields whose parent was untouched).
  • Inactive fields cannot be answered — replies containing answers for inactive fields fail with Form.InvalidAnswerError. Combined with unanswered⇒false, inactivity cascades through chains (hiding B falsifies every condition referencing B) with no recursive evaluation needed.
  • required continues to apply only while a field is active.

Create-time validation (new Form.InvalidFormError)

Invalid when definitions are rejected at create/ask instead of silently never matching, so the authoring caller (usually an LLM tool call) sees an actionable error:

  • when.key must reference an earlier field (also rules out cycles)
  • duplicate field keys are rejected
  • value type must match the referenced field's type
  • when the referenced field has closed options, value must be one of them

The server handler maps Form.InvalidFormError to the existing InvalidRequestError (400) — no new protocol errors or routes.

Verification

  • bun typecheck in packages/schema, packages/core, packages/protocol, packages/server, packages/client, packages/sdk/js, packages/opencode
  • bun test test/form.test.ts in packages/core — 7 pass (4 new: gating + inactive rejection, multiselect inclusion, unanswered/cascade semantics, creation validation)
  • bun test test/event-manifest.test.ts in packages/schema
  • bun test + bun run check:generated in packages/client
  • HttpApi exerciser form scenarios 6/6

@rekram1-node rekram1-node changed the base branch from form-elicitation to v2 July 3, 2026 09:23
@rekram1-node rekram1-node merged commit 85fde8c into v2 Jul 3, 2026
8 checks passed
@rekram1-node rekram1-node deleted the form-when branch July 3, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant