You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Console FormPage still drops the other three conditional-rule surfaces after #5594: section-level visibleWhen/visibleOn, and the object-level field rules visibleWhen/readonlyWhen/requiredWhen #5627
Found while implementing #5594 (wiring the view-level field visibility predicate into apps/console/src/components/FormPage.tsx). Filed unassigned for PM triage — outside that
card's scope: its triage fence declared it "the predicate wiring plus a regression pin",
and the two surfaces below are different keys with different user-visible consequences, so
folding them in would have been unreviewable scope creep rather than a bounded fix.
Verified on 8c87f0583 (the merge-base of the #5594 branch), before and after that change.
Mechanism
FormPage.tsx is the second, independent form renderer — its own buildSections, its own
JSX, serving both /f/:slug (public, anonymous) and /forms/:name (internal). After #5594 it honours one of the four conditional-rule surfaces the sibling chain honours.
The other three are still dropped, and both drops happen in the same place: the two local
types that describe the payloads, which admit none of these keys, so nothing downstream can
read them.
1. Section-level visibleWhen / visibleOn
The local section type declares four keys and no visibility at all:
and the render maps every section unconditionally (FormPage.tsx:1398):
{sections.map((sec, i) => (
The app-shell counterpart does declare and honour it — FormSectionSpec in packages/app-shell/src/views/metadata-admin/SchemaForm.tsx carries visibleWhen/visibleOn (documented there as "Canonical section visibility predicate
(ADR-0089)"), and SchemaFormBody filters sections through readVisibility before
rendering. So a section an author conditioned away renders in full on the two console form
routes, including the public one.
2. Object-level field rules visibleWhen / readonlyWhen / requiredWhen
The local object-schema field type admits eight keys and none of the ADR-0036 rules:
buildSections reads only those, so RenderableField.readonly is override.readonly ?? false
and required is override.required ?? def.required ?? false — static, never conditional.
The sibling chain carries all three out of the object schema and resolves them through resolveFieldRuleState — packages/plugin-form/src/sectionFields.ts, fromObjectSchema:
// Field-level conditional rules (ADR-0036) — the form renderer resolves// them via `resolveFieldRuleState`; without this copy a sectioned form// silently dropped rules that the flat (schema-order) form honors.visibleWhen: field.visibleWhen,readonlyWhen: field.readonlyWhen,requiredWhen: field.requiredWhen,
Note that #5594's fix reads the view-level predicate off the FormField override only.
An object-level visibleWhen — authored on the object's field, not on the form view — is a
separate slot the sibling keeps separate on purpose (sectionFields.ts routes the view
predicate into visibleOn precisely so the object rule is never clobbered), and this
renderer reads neither of those two.
Searched open issues before filing (section visibility / FormSectionSpec / readonlyWhen
/ requiredWhen / console form renderer / conditional field phrasings). #5596 is the only
open match and it is about the type declarations, not the evaluation.
Severity note
User-reachable on the public /f/:slug route, same as #5594 — and the object-level half is
worse than fail-open hiding: a readonlyWhen that should lock a field leaves it editable,
which pairs badly with the server's fail-CLOSED behaviour for the unbound-scope case
(objectstack#4889, described in packages/core/src/evaluator/fieldRules.ts) — the user
edits, the save reports success, and the value never lands.
Two questions a fix has to answer rather than assume, which is part of why this is filed
instead of folded in:
The two type excerpts have their generic angle brackets spelled out as Array[...] —
GitHub's body sanitizer eats short angle-bracket fragments, fenced code included (this was
measured on the #5594 PR body, which had Record of string to unknown silently reduced
to Record). Read the real declarations at apps/console/src/components/FormPage.tsx.
Found while implementing #5594 (wiring the view-level field visibility predicate into
apps/console/src/components/FormPage.tsx). Filed unassigned for PM triage — outside thatcard's scope: its triage fence declared it "the predicate wiring plus a regression pin",
and the two surfaces below are different keys with different user-visible consequences, so
folding them in would have been unreviewable scope creep rather than a bounded fix.
Verified on
8c87f0583(the merge-base of the #5594 branch), before and after that change.Mechanism
FormPage.tsxis the second, independent form renderer — its ownbuildSections, its ownJSX, serving both
/f/:slug(public, anonymous) and/forms/:name(internal). After#5594 it honours one of the four conditional-rule surfaces the sibling chain honours.
The other three are still dropped, and both drops happen in the same place: the two local
types that describe the payloads, which admit none of these keys, so nothing downstream can
read them.
1. Section-level
visibleWhen/visibleOnThe local section type declares four keys and no visibility at all:
and the render maps every section unconditionally (
FormPage.tsx:1398):The app-shell counterpart does declare and honour it —
FormSectionSpecinpackages/app-shell/src/views/metadata-admin/SchemaForm.tsxcarriesvisibleWhen/visibleOn(documented there as "Canonical section visibility predicate(ADR-0089)"), and
SchemaFormBodyfilters sections throughreadVisibilitybeforerendering. So a section an author conditioned away renders in full on the two console form
routes, including the public one.
2. Object-level field rules
visibleWhen/readonlyWhen/requiredWhenThe local object-schema field type admits eight keys and none of the ADR-0036 rules:
buildSectionsreads only those, soRenderableField.readonlyisoverride.readonly ?? falseand
requiredisoverride.required ?? def.required ?? false— static, never conditional.The sibling chain carries all three out of the object schema and resolves them through
resolveFieldRuleState—packages/plugin-form/src/sectionFields.ts,fromObjectSchema:Note that #5594's fix reads the view-level predicate off the
FormFieldoverride only.An object-level
visibleWhen— authored on the object's field, not on the form view — is aseparate slot the sibling keeps separate on purpose (
sectionFields.tsroutes the viewpredicate into
visibleOnprecisely so the object rule is never clobbered), and thisrenderer reads neither of those two.
Why this is not a duplicate
FormField.visibleOnon the plugin-form chain.visibleWhen/readonlyWhen/requiredWhen(andgroup) — ModalForm's identical builder carries them #4755:DrawerForm's no-sections field builder dropping the same three object-levelrules — same class, a third renderer, closed.
deliberately left.
FormViewSpec/FormSectionSpeceachhand-declared twice). Adjacent and relevant — converging
FormSectionSpecwould make thesection keys declarable here — but declarable is not evaluated. That is exactly the
[finding] A THIRD inline copy of the form-field authoring contract lives in apps/console FormPage.tsx — objectui#5040 converged only the app-shell two #5542 / Console FormPage (the standalone /forms and internal FormView renderer) never evaluates visibleWhen/visibleOn — objectui#2212 was fixed in the OTHER form renderer #5594 relationship repeating one level up: [finding] A THIRD inline copy of the form-field authoring contract lives in apps/console FormPage.tsx — objectui#5040 converged only the app-shell two #5542 made
visibleWhendeclarable onthe console's field type, and the predicate still rendered unconditionally until Console FormPage (the standalone /forms and internal FormView renderer) never evaluates visibleWhen/visibleOn — objectui#2212 was fixed in the OTHER form renderer #5594.
Searched open issues before filing (section visibility /
FormSectionSpec/readonlyWhen/
requiredWhen/ console form renderer / conditional field phrasings). #5596 is the onlyopen match and it is about the type declarations, not the evaluation.
Severity note
User-reachable on the public
/f/:slugroute, same as #5594 — and the object-level half isworse than fail-open hiding: a
readonlyWhenthat should lock a field leaves it editable,which pairs badly with the server's fail-CLOSED behaviour for the unbound-scope case
(
objectstack#4889, described inpackages/core/src/evaluator/fieldRules.ts) — the useredits, the save reports success, and the value never lands.
Two questions a fix has to answer rather than assume, which is part of why this is filed
instead of folded in:
submit — Console FormPage (the standalone /forms and internal FormView renderer) never evaluates visibleWhen/visibleOn — objectui#2212 was fixed in the OTHER form renderer #5594 deliberately kept conditional visibility a rendering rule for fields
(a hidden field still submits its value, matching the plugin-form chain), and the same
question repeats at section granularity.
requiredWhenhere needs theserverOwnedValuecarve-outresolveFieldRuleStateapplies (A required field whose
defaultValueis a runtime token (NOW()/current_user) cannot be submitted from a create form #4069 /requiredWhen+ a runtimedefaultValuestill deadlocks a create form (the conditional half of #4069) #4085), given this route serves both create and edit (type: 'form'action fired from a record opens an empty CREATE form —/forms/:nameignores the?recordId=ActionRunner forwards #4278).Note on the code blocks above
The two type excerpts have their generic angle brackets spelled out as
Array[...]—GitHub's body sanitizer eats short angle-bracket fragments, fenced code included (this was
measured on the #5594 PR body, which had
Recordofstringtounknownsilently reducedto
Record). Read the real declarations atapps/console/src/components/FormPage.tsx.Generated by Claude Code