feat(types)!: retire ComponentInput.inputType as an ADR-0049 tombstone (objectui#5905, ruled option B) - #7639
Merged
Conversation
…NED, not removed
The FROM -> TO list in the objectui#5905 changeset said "removed" for all four
keys, contradicting the paragraph directly below it ("Deleting the members
outright was the option NOT taken") and describing the exact option the
maintainer ruled against: under a non-strict z.object a deleted key is silently
STRIPPED, which trades one silent no-op for another.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
The fifth and last key objectui#5905 named, ruled by the maintainer on 2026-08-31 (option B). It was held back from the four-sibling retirement because its defect was a different one: min/max/step/placeholder were declared-and-UNREAD, while inputType was declared-and-DROPPED -- the repository really did author it (plugin-markdown's `content` input) while the manifest serializer dropped it, so retiring it had to rule on that registration first. - delete the no-op `inputType: 'textarea'` write in plugin-markdown - tombstone ComponentInput.inputType: `?: never` on the interface plus a retirementTombstone() named refusal on the Zod mirror, matching the four siblings exactly - flip three pins rather than delete them: plugin-markdown's index.test.ts and the two fork-half controls in component-input-retired-constraint-keys.test.ts - correct the stale "the fork is recorded ... until then this stays a live, writable key" wording in base.ts, base.zod.ts and widget.ts, which this change falsifies Deleting the member outright stays the option NOT taken: ComponentInputSchema is a non-strict z.object, so an undeclared key is silently stripped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Contributor
✅ 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
|
Collaborator
Landing — contract review PASS at
|
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.
Fixes #5905
Retires
ComponentInput.inputType— the fifth and last key the card named — under the maintainer ruling of 2026-08-31 (director seat summon 6, decision batch 14), option B. Quoted verbatim and untranslated, as the ruling was given:The four ruled edits
inputType: 'textarea'onplugin-markdown'scontentinput.ComponentInput.inputType—?: neveron the interface (packages/types/src/base.ts) plus aretirementTombstone()named refusal on the Zod mirror (packages/types/src/zod/base.zod.ts), matching the four siblings member for member.plugin-markdown'sindex.test.ts(which asserted the write) and the two fork-half controls incomponent-input-retired-constraint-keys.test.ts, one type-level and one parse-level.Clause-②: YES — this changes the accept set
Stated plainly for review, because it is the whole point of the label:
ComponentInput.inputTypeparsed GREEN, and the value was then dropped by the manifest serializer — a silent no-op.code: 'invalid_type', the key named in the issuepath, and the migration note as the message.That is a narrowing of a published type's member surface plus a new Zod refusal arm, so
needs:contract-reviewis on both carriers and this PR stays a draft for the director seat. It is not enqueued.Deleting the member outright stays the option NOT taken, for the reason the four siblings established and which this repo pins in one run:
ComponentInputSchemais a non-strictz.object, so an undeclared key is silently stripped. The tombstone is what converts a write from outside this repository — the half the card could not measure — into a named refusal carrying its own remedy.Option A, teaching
sdui-parserto forward the key, is REFUSED on record: the only thing resembling demand for it was a write that had never taken effect. The neighbouring 2026-08-17 expression-ceiling ruling is untouched and stays deferred, reopen condition unchanged.Measurement — re-taken on this branch's base, not inherited
The census, with a lit control. A structural scan of every
inputs:array region in the repository (the only route to aComponentInputvalue) over all tracked TS/TSX/JS sources: 211 regions.inputTypescores exactly one authoring site — theplugin-markdownregistration — plus one occurrence insidebase.ts's own doc prose. The same pass over the same regions scoresname953,type969,label966,description194,enum119,required86,binding4, so the instrument was demonstrably not blind;min/max/step/placeholderscore 0, consistent with their landed tombstones.The other 192 in-repo
inputTypehits are a different face, excluded one by one rather than by eyeball:FormField.inputType(zod/form.zod.ts:195,566and the JSON/doc examples that spelltype: 'input'inside afields:array), the text-input renderer's prop,SchemaBuilder.inputType(which writes a node schema, sibling tolabelandplaceholderon the same builder), and the identifierinputTypeArmsinsdui-parser. None sits on aComponentInput.The publication path, re-confirmed.
packages/sdui-parser/src/index.tsforwards exactly six keys per input —name,type,required,enum,binding,description— so an authoredinputTypecould not reach the publishedsdui.manifest.jsoneven in principle. Deleting the write therefore costs zero capability.Ablation — and which instrument actually holds the pin
Predictions were written down before the run; observed matched predicted exactly. The mutation restored all three halves (un-tombstoned the interface member and the mirror arm, put the
plugin-markdownwrite back).Mutation proved on disk before anything was measured: anchored counts for both the injected and the deleted text, plus blob-hash inequality against the
HEADblob for all three files. The types package was rebuilt on the mutation leg and a dist preflight confirmeddist/base.d.tscarried the mutation — necessary because vitest aliases@object-ui/typesto source whileplugin-markdown'stsconfig.test.jsondropspathsand resolves through the built declarations. Files stayed well-formed: the build passed and vitest collected 43 tests, so the reds below are failing assertions, not a failure to collect.inputType(loop case)inputTypenow parses REDplugin-markdownno longer authors ittypestest programcomponent-input-retired-constraint-keys.test.ts(141,7): error TS2578plugin-markdowntest programindex.test.ts(81,9): error TS2578⇒ The tombstone pin is held by
type-check, not by vitest. A green vitest exit code says nothing about it; that row is in the table precisely so nobody reads it as evidence. The four sibling directives did not error on either leg, which is that leg's own non-vacuity control.Both pin files were proved to be in their checked programs rather than assumed:
tsc -p tsconfig.test.json --noEmit --listFileslistscomponent-input-retired-constraint-keys.test.tsamong 561 program files andplugin-markdown/src/index.test.tsamong 1674.Restore proved two ways —
git diff HEADempty for all three paths, and blob-hash equality against theHEADblob for each — and the types package was rebuilt on the restore leg as well, with a dist preflight confirming the marker is gone. Without that second rebuild the mutated declarations would have stayed indistand every later measurement would have been taken against the wrong tree.The stale wording, which is item 4's real payload
base.tsandzod/base.zod.tsboth still said the fork was "recorded on objectui#5905 for a ruling; until then this stays a live, writable key". The 2026-08-31 ruling closed that fork. Anyone who greps the source instead of the comment thread met an open question that no longer existed — which is very close to how this card's previous dispatch went out with the wrong scope. Both now record the ruling.One file beyond the brief, declared rather than slipped in:
packages/types/src/widget.tscarried the same wording — it calledinputType"the open fork objectui#5905 reported" and described the five as "ONE live key plus four unwritable ones". This change falsifies that sentence, so it is collateral of this diff rather than an unrelated tidy-up. Its doc block is pinned by__tests__/widget-input-control-vocabulary.test.ts, which requires the block to keep naming all five keys in backticks, to keepoptions/enum/ComponentInput, and to keep the phraseNOT NOW; the rewrite was checked against the test's own doc-block extraction and that test passes. No fence covers this file.The old changeset's FROM → TO list said the four were "removed" when they were tombstoned — contradicting its own next paragraph. Corrected.
Fences — checked, not assumed
titledeclaration #7633 holdspackages/types/src/complex.tsand__tests__/zod-mirror-parity.test.ts. Neither is in this diff. The previous round could only infer that a symmetric tombstone would not need them; that inference is now measured —zod-mirror-parity.test.tswas run by name and passes unmodified, because it pairsComponentInputSchemawith the TS twin without carrying a per-key entry for any tombstone.data.provider === 'object'folds could collapse onto one shared reader — the seventh now lives innormalizeListViewSchema#7627, dispatch finding(plugin-grid, fields): the snake_case half of the lookup dialect —display_field,description_field,lookup_filters,id_field— is refused by the strictFieldSchema, so no spec-compliant producer can emit it #7155, PR refactor(examples): drop the inert roottitlefrom six catalog dashboards #7634, orcontent/docs/releases/.node scripts/check-governed-queue-guard.mjs --teston all 8 changed paths:NOT GOVERNED — 8 path(s) checked against 5 governed surface(s); none matched.Verification — all at
d3f4cca9, from the repo rootExit codes captured by redirect, never through a pipe.
pnpm exec vitest run packages/types/ packages/plugin-markdown/— 106 files, 1760 tests passedpnpm exec vitest runonzod-mirror-parity,widget-input-control-vocabulary,component-input-retired-constraint-keysandpackages/plugin-markdown/— 7 files, 67 tests passedpnpm exec turbo run type-checkrepo-wide — 81 successful, 81 total (the net that matters for a tombstone)pnpm exec turbo run build— 44 successful, 44 totalpnpm lintrepo-wide — exit 0, 0 errors (warnings are the pre-existingno-explicit-any/ react-refresh population; the full scan was run rather than narrowed, so no narrowing needs declaring)node scripts/check-changeset-presence.mjs— exit 0: "6 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"check:control-bytes(6240 files scanned),check:sdui-registration-pins,check:skill-examples,check:published-tsconfig-exclude,check:doc-snippets(452 of 452 blocks judged),check:doc-types,check:readme-exports— all exit 0Spec note: readings were taken against
@objectstack/spec17.2.0, which is what the lockfile resolves; nothing was bumped. 17.3.0 has shipped but changes nothing onComponentInput.Filed as its own card, deliberately out of scope here
objectui#7636 — the published
skills/objectui/guides/plugin-development.mddocuments all five of these keys as writable optionals, and has been wrong about four of them since 2026-08-31, independently of this change. It is left alone deliberately:skills/**is a governed surface here and carries a line-count ratchet, and this dispatch carried no budget for it. The card also records the more interesting half —check:skill-examplesjudges that fence and stays green, because the snippet re-declaresComponentInputlocally instead of importing it, so the gate compiles a private copy and cannot see the drift.Generated by Claude Code