Uh oh!
There was an error while loading. Please reload this page.
fix(types): disabled inherits BaseSchema's boolean | string on the 18 schemas that narrowed it - #7240
Conversation
… inherits BaseSchema's `boolean | string` `visible` and `disabled` are twins: objectui#4581 widened both on `BaseSchema` to `boolean | string` because `SchemaRenderer` evaluates both through `evaluator.evaluateCondition` rather than reading either as a boolean. After that widening, 0 of the 124 `extends BaseSchema` interfaces redeclared `visible`, while 18 still carried a pre-widening `disabled?: boolean` of their own — 15 in `form.ts`, `ActionSchema` in `crud.ts`, `CollapsibleSchema` and `ToggleGroupSchema` in `disclosure.ts` — with matching `z.boolean()` mirrors. A predicate string on `disabled` was therefore a type error and a zod refusal on exactly the schemas an author reaches for first. Maintainer ruling 2026-09-01 (option 1, scoped to `disabled`): the narrowings go and the base union stands. Removed on both faces rather than redeclared as the union — the interfaces inherit the member the way they always inherited `visible`, and the mirrors inherit `base.zod.ts`'s `z.union([z.boolean(), z.string()])` through `.extend()`'s merged `.shape` — the route `ChatbotSchema` took in objectui#6169, so there is no second spelling of the union to drift. Out of scope per the ruling and untouched: `label` / `description` (i18n semantics, own ruling pending) and the six independent `disabled?: boolean` declarations in these files on shapes that do not extend `BaseSchema` (`SelectOption`, `RadioOption`, `FormField`, `ComboboxOption`, `AccordionItem`, `ToggleGroupItem`). Pinned in `disabled-twin-symmetry-7087.test.ts`: the 18 interfaces' `disabled` is exactly `boolean | string | undefined` (invariant `Equal`, with `visible` as the twin control), each mirror parses a predicate string on both twins and still refuses a number at path `disabled`, and the six independent declarations stay `boolean` on both faces. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
os-litant
commented
Sep 2, 2026
Parked draft — expected-red list (signature level) and the release condition
Release condition: objectui#7238 merged into Expected red on head Checks that fail on that root, each read from its own job log: Any other red signature on this PR is a new problem, not the dependency — treat it as such. ⛔ Do not re-run the failing jobs; they will not change until the base carries #7238. Generated by Claude Code |
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7087
Maintainer ruling 2026-09-01 (director decision batch D, card comment 5487486816, verbatim 「同意」): option 1, scoped to
disabled— drop the 18 narrowings, restore twin symmetry withvisible.label/description(i18n semantics, own ruling pending) and the independent non-BaseSchemadisableddeclarations are OUT per the ruling and untouched.Clause-② content limb: this widens the accepted authoring surface on published types —
needs:contract-reviewon this PR and on the card. The accept-set delta is written out below so the reviewer does not have to re-derive it.Accept-set delta
Population re-derived on
origin/main@67dadd602by ENCLOSING interface (not by line): 24disabled?: boolean;lines across the three files — 18 insideextends BaseSchemainterfaces (the card's census at592acafbe, unchanged; no interface moved), 6 on independent shapes.ButtonSchemaInputSchemaTextareaSchemaSelectSchemaCheckboxSchemaRadioGroupSchemaSwitchSchemaToggleSchemaSliderSchemaFileUploadSchemaDatePickerSchemaCalendarSchemaInputOTPSchemaFormSchemaComboboxSchemapackages/types/src/form.tsdisabled?: booleanBaseSchema.disabled?: boolean | stringActionSchemapackages/types/src/crud.tsdisabled?: booleanboolean | stringCollapsibleSchemaToggleGroupSchemapackages/types/src/disclosure.tsdisabled?: booleanboolean | stringZod mirrors (
packages/types/src/zod/form.zod.ts× 15,crud.zod.ts× 1,disclosure.zod.ts× 2): the 18disabled: z.boolean().optional().describe(…)lines are removed from the matchingBaseSchema.extend({ … })blocks; each mirror now inheritsbase.zod.ts'sz.union([z.boolean(), z.string()]).optional()through.extend()'s merged.shape. Measured on the mirrors: a predicate string ondisabledgoes refused → accepted (18/18);disabled: trueaccepted before and after;disabled: 1refused before and after at pathdisabled.Untouched, and pinned as the scope guard (both faces stay
boolean):SelectOption,RadioOption,FormField,ComboboxOption(form.ts),AccordionItem,ToggleGroupItem(disclosure.ts) — the 6 independent declarations in these files; the rest of that family lives in files this PR does not touch.Mechanism — deviation from the dispatch's Zone-2 assumption 2 ("reuse the exact union form for parity"): the member is REMOVED on both faces, not re-spelled as the union.
visibleis inherited on all 124 extenders, andChatbotSchemaalready took this exact route fordisabledin objectui#6169 (its pin:.extend()'s.shapemerges the parent's fields into the child's … re-declaring it would have SHADOWED the inheritedboolean | string). Deletion leaves no second spelling to drift; the invariant pin below is what stops a re-narrowing. Thezod-mirror-parityledger carries nodisabledentry for any of the 18 pairs before or after (suite green unchanged).No reader was widened. Files:
packages/types/src/{form,crud,disclosure}.ts, their three zod mirrors, one pin, one changeset (@object-ui/types: minor — additive for authors).Readers — measured, NOT changed here (dispatch Zone-2 item 3) → #7238
The ruling's premise holds at the renderer:
packages/react/src/SchemaRenderer.tsx:1289-1299gatesdisabled/disabledOnthroughhasDeclaredPredicate+evaluateEnablementPredicateand forwards the VERDICT as a realdisabledprop (:1584).ActionSchema.disabled's three readers are predicate-aware (ActionRunner.ts:1004-1015,DeclaredActionsBar.tsx:179/394,data-table.tsx:401).But the
schemahanded to the widget isevaluatedSchemaitself (rawdisabledretained), and seven in-scope widgets re-read the RAW value.pnpm --filter @object-ui/components type-checkon this head (closure built) → 9 × TS2322Type 'string | boolean | undefined' is not assignable to type 'boolean | undefined':disabled={schema.disabled}—renderers/form/input.tsx:48,textarea.tsx:45,checkbox.tsx:44,select.tsx:52,combobox.tsx:28,renderers/disclosure/collapsible.tsx:20. Runtime stays correct throughSchemaRenderer(the host'sdisabledprop is spread after the raw one;pickDomPropsforwards anundefinedverdict too) — the narrowing was load-bearing for their compile only.renderers/form/form.tsx:1008destructuresdisabledfromschemaand discards the host verdict (_disabledProp,:2804); feeds:2653,:2994,:3006— runtime defect: a predicate string greys the whole form out regardless of verdict.renderers/form/button.tsx:42schema.disabled || props.disabled || isLoading— compiles (propsisany), same runtime defect onui:button. Not among the 9.Both runtime defects are reachable today via JSON and via
BaseSchema-typed nodes; this PR makes them reachable from the concrete TS types and turns the passthroughs into type errors. Widening a reader is Clause-② content beyond the ruling, so it is filed as #7238 with the fix shape (plugin-chatbot/src/renderer.tsx's one-carrier read) for the seat to route: either it rides here under the same review, or lands ahead of this PR. Until then, CI's Type Check job is expected RED on exactly those 9 lines; everypackages/typesgate is green.Verification — head
06103d1(all builds/tests viascripts/pm/os-verify-lock.sh)pnpm --filter @object-ui/types build→✓ dist completeness: 1 package(s) complete (118 emitted files verified)pnpm exec vitest run packages/types/src/__tests__/disabled-twin-symmetry-7087.test.ts→Test Files 1 passed (1)·Tests 103 passed (103)pnpm exec vitest run packages/types/→Test Files 85 passed (85)·Tests 1166 passed (1166)pnpm --filter @object-ui/types type-check(tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json) → exit 0, no diagnostics.tsconfig.test.jsonincludessrc/**/*.test.ts, so the pin's type-level assertions ARE compiled — proven by ablation leg A going red through this same project.pnpm exec turbo run build --filter='@object-ui/components^...' --concurrency=2→Tasks: 7 successful, 7 totalpnpm --filter @object-ui/components type-check→ exit 2, 9 × TS2322 (above; expected, routed via finding(components): seven widgets re-read the rawschema.disabledbeside SchemaRenderer's evaluated verdict — 9 TS2322 once the #7087 narrowings drop, andui:button/formgrey out on any predicate string #7238)pnpm check:spec-symbols→✅ spec symbol derivation: 1333 files scanned against 4959 spec export names; 16 declared dialects, 0 untriaged collisions in 0 packages.pnpm check:doc-types→✅ Every documented component type is registered.pnpm check:control-bytes→✅ check-control-bytes: OK (scanned 5998 tracked text file(s); skipped 85 binary).node scripts/check-changeset-presence.mjs(aftergit add) →✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/7087-disabled-twin-symmetry.md.node scripts/check-changeset-no-major.mjs→✅ No changeset declares a major bump.pnpm exec eslinton the 7 touched source/test files → exit 0 (0 errors; 13 pre-existingno-explicit-anywarnings inform.ts/crud.zod.ts, none on new lines)node scripts/check-governed-queue-guard.mjs --teston all 8 paths →✅ NOT GOVERNED — 8 path(s) checked against 5 governed surface(s); none matched.NOT MEASURED locally (CI-owned; each would need the full workspace built):
pnpm check:readme-exports(population COLLAPSED —packagesRead: found 8, floor is 25),pnpm check:doc-snippets(exit 2PRECONDITION NOT MET, 21 packages in its build filter unbuilt),check:dist-completeness --all(per-package copy ran inside each of the 8 builds), repo-widepnpm lint, and the full downstream sweeppnpm --filter '...@object-ui/types' type-check(43 consumers). The downstream sweep is narrowed to@object-ui/componentsby a read census:schema.disabled/disableddestructured fromschemaacrosspackages/*/src+apps/*/src(tests excluded) hits only the components widgets above,plugin-chatbot(ChatbotSchema, already the union),core/src/builder/schema-builder.ts:76(assigns a boolean INTO the slot — narrower into wider cannot go red) and the three predicate-awareActionSchemareaders.git fetch origin main && git merge origin/mainbefore opening:Already up to date(origin/mainstill67dadd602; the parallel #7188 lane had not landed), so no re-run was owed to a merge.Ablation (after commit; each leg trap-restored, mutation and restore proven by blob hash +
git diff HEADempty + anchor line counts; the pin imports its subjects by relative SOURCE path, so no rebuild belongs to either leg)67dadd602blobpackages/types/src/disclosure.ts(anchordisabled?: boolean;2 → 4)tsc -p packages/types/tsconfig.test.jsondisabled-twin-symmetry-7087.test.ts(146,52): TS2344=assertionDisabledIsBaseUnion;assertionVisibleTwinControl(line 148) cleanpackages/types/src/zod/disclosure.zod.ts(anchor 2 → 4)packages/types/src/zod/form.zod.ts(anchor 4 → 19)After each leg: on-disk blob == HEAD blob,
git diff HEADempty, anchor count back (2 / 2 / 4). Final tree: 0 dirty paths.Also filed
schema.disabledbeside SchemaRenderer's evaluated verdict — 9 TS2322 once the #7087 narrowings drop, andui:button/formgrey out on any predicate string #7238 — the seven raw-read widgets above (unassigned, PM to route).disabled?: booleanin their illustrative interface — stale once #7087 drops the narrowings toboolean | string#7239 — 13content/docs/components/**pages spell the schema's owndisabled?: booleanin their illustrative interface (sub-issue of finding(types): 18 schemas narrow inheriteddisabledtobooleanwhile 0 narrow its twinvisible— no ruling says which is intended #7087; docs-only; not gated because those pages declare their own interfaces, objectui#6143).Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
🤖 Generated with Claude Code
https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Generated by Claude Code