Measured while wiring the disabled fault diagnostic (#6445). Filed unassigned, outside that card's face — it is a packages/core validation-rule question, not the react wiring.
The rule
packages/core/src/validation/schema-validator.ts, BASE_SCHEMA_RULES:
visible: {required: false,validate: (value: any)=>typeofvalue==='boolean',message: 'visible must be a boolean'},disabled: {required: false,validate: (value: any)=>typeofvalue==='boolean',message: 'disabled must be a boolean'}Both keys are expressions everywhere else in the system. AGENTS.md §4 declares the protocol as hidden?: string; // expression: "${data.role != 'admin'}" / disabled?: string; // expression; SchemaRenderer evaluates them through hasDeclaredPredicate + evaluateCondition (the #3862 / #3955 rulings are entirely about which expression spellings count as declared); packages/spec normalizes them into { dialect: 'cel', source } envelopes. A boolean is one of the shapes the renderer accepts, not the only one.
What it costs
SchemaRenderer runs validateSchemaOnce in development for every schema object, so a perfectly valid node
{ "type": "button", "disabled": "${record.stage == 'closed'}" }prints
[ObjectUI] Invalid schema detected:
schema.disabled: disabled must be a boolean
and gets data-obj-schema-invalid on its host element — the visual cue apps are told to hang a red outline off. A false positive on the authoring form the docs teach.
Measured (dev build, packages/react, one node): the line above is emitted alongside the genuine #6445 fault line, so an author who has just been told exactly which predicate failed is told in the next breath that predicates are not allowed. The false line is the load-bearing one for anyone who trusts the validator: it points at the shape, not the fault.
The same rule fires for visible, which the visibility chain has evaluated as an expression since long before #5454.
Why this is filed rather than fixed
The rule that replaces it is a real decision, not a typo fix: disabled legitimately admits boolean | string | { dialect, source }, and the repo already owns the one definition of "is this a declared predicate?" (hasDeclaredPredicate, core's evaluator/declaredPredicate.ts, #3850's ruling). Whether this validator should reuse that definition, accept the three shapes structurally, or drop the two keys from BASE_SCHEMA_RULES entirely — and whether anything currently depends on the false positive — wants a decision and its own pins. It also touches packages/core, which #6445 was explicitly scoped out of.
Adjacent, not the same: #6318 is about the zod safeValidateSchema surface; this is the hand-rolled BASE_SCHEMA_RULES table behind validateSchema / validateSchemaOnce.
Measured while wiring the
disabledfault diagnostic (#6445). Filed unassigned, outside that card's face — it is apackages/corevalidation-rule question, not the react wiring.The rule
packages/core/src/validation/schema-validator.ts,BASE_SCHEMA_RULES:Both keys are expressions everywhere else in the system.
AGENTS.md§4 declares the protocol ashidden?: string; // expression: "${data.role != 'admin'}"/disabled?: string; // expression;SchemaRendererevaluates them throughhasDeclaredPredicate+evaluateCondition(the #3862 / #3955 rulings are entirely about which expression spellings count as declared);packages/specnormalizes them into{ dialect: 'cel', source }envelopes. A boolean is one of the shapes the renderer accepts, not the only one.What it costs
SchemaRendererrunsvalidateSchemaOncein development for every schema object, so a perfectly valid node{ "type": "button", "disabled": "${record.stage == 'closed'}" }prints
and gets
data-obj-schema-invalidon its host element — the visual cue apps are told to hang a red outline off. A false positive on the authoring form the docs teach.Measured (dev build,
packages/react, one node): the line above is emitted alongside the genuine #6445 fault line, so an author who has just been told exactly which predicate failed is told in the next breath that predicates are not allowed. The false line is the load-bearing one for anyone who trusts the validator: it points at the shape, not the fault.The same rule fires for
visible, which the visibility chain has evaluated as an expression since long before #5454.Why this is filed rather than fixed
The rule that replaces it is a real decision, not a typo fix:
disabledlegitimately admitsboolean | string | { dialect, source }, and the repo already owns the one definition of "is this a declared predicate?" (hasDeclaredPredicate, core'sevaluator/declaredPredicate.ts, #3850's ruling). Whether this validator should reuse that definition, accept the three shapes structurally, or drop the two keys fromBASE_SCHEMA_RULESentirely — and whether anything currently depends on the false positive — wants a decision and its own pins. It also touchespackages/core, which #6445 was explicitly scoped out of.Adjacent, not the same: #6318 is about the zod
safeValidateSchemasurface; this is the hand-rolledBASE_SCHEMA_RULEStable behindvalidateSchema/validateSchemaOnce.