feat(core): rework form when conditions#35115
Merged
Merged
Conversation
7cd59d2 to
96ac0de
Compare
This was referenced Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #35108. Reworks the form
whenconditional-visibility contract, which was previously under-specified and partly broken (awhentargeting a boolean or number field could never match becausevaluewas string-only and compared with===).Schema (
Form.When)whenis now always an array (When[]), evaluated as AND.valueisstring | number | boolean, matching the referenced field's type.eq/neq. Extensions (in, etc.) can be added later without breaking the shape.Semantics (documented on the schema and enforced in core)
eqmeans "selection includes value",neqmeans "does not include".neqactivated fields whose parent was untouched).Form.InvalidAnswerError. Combined with unanswered⇒false, inactivity cascades through chains (hiding B falsifies every condition referencing B) with no recursive evaluation needed.requiredcontinues to apply only while a field is active.Create-time validation (new
Form.InvalidFormError)Invalid
whendefinitions are rejected atcreate/askinstead of silently never matching, so the authoring caller (usually an LLM tool call) sees an actionable error:when.keymust reference an earlier field (also rules out cycles)valuetype must match the referenced field's typeoptions,valuemust be one of themThe server handler maps
Form.InvalidFormErrorto the existingInvalidRequestError(400) — no new protocol errors or routes.Verification
bun typecheckinpackages/schema,packages/core,packages/protocol,packages/server,packages/client,packages/sdk/js,packages/opencodebun test test/form.test.tsinpackages/core— 7 pass (4 new: gating + inactive rejection, multiselect inclusion, unanswered/cascade semantics, creation validation)bun test test/event-manifest.test.tsinpackages/schemabun test+bun run check:generatedinpackages/client