fix(components): publish element:record_picker.filter, the A-class key #3808's triage dropped (#3830) - #4112
Merged
Conversation
…key #3808's triage dropped (#3830) `filter` appears in objectui#3808's raw key dump for this block and then in none of its A / B / C lists, so the change that added the repo-wide parity gate exempted it by name instead of declaring it. It is the fourth gap of exactly the same shape as the four that PR #3841 fixed: `@objectstack/spec` declares `ElementRecordPickerProps.filter`, the renderer has read it all along (`composed?.filter ?? props.filter` -> `query.$filter`), and the registry `inputs` never mentioned it. `element:record_picker` is not in `PUBLIC_BLOCKS` ("record picking is a field widget, not a page block"), so the gap was not in `sdui.manifest.json` — it was in the JSX-page compiler's prop whitelist, which `renderers/layout/page.tsx` builds from `getKnownTypes()` plus these same `inputs`. Verified end to end rather than argued: with the declaration reverted, `compile()` over the live registration returns `<element:record_picker> has no prop "filter"` on a key the renderer then filters the entire candidate set by. The description is derived from what the renderer DOES, because the one thing an author cannot read off the spec is which of the two places they may write a filter wins: a node-level `dataSource` filter (itself AND-combined with any saved `view` it names) is taken and this top-level `filter` is DROPPED, not merged. `type: 'object'`, from the spec's actual shape on the resolved pin and not the `'array'` the issue's landing sketch guessed. `filter` is `FilterConditionSchema`, i.e. `z.record(z.string(), z.unknown())` intersected with the `$and`/`$or`/`$not` group, so a rule array is rejected — measured with `safeParse`, and `sdui-parser`'s `checkType` object arm draws exactly the same partition. This is the one key in the family where `ComponentInput`'s coarse typing costs nothing, so unlike `element:text_input.defaultValue` there is no narrowing to disclose in the description (data point for objectui#3832, not a widening of this card). The gate's explicit exemption for this key is deleted in the same change, as its own `carries no stale unpublished-key exemption` assertion demands, and the key joins #3808's four in the by-name "declared, not merely not-failing" pin — now five. Reverse verification (declaration reverted, exemption removal kept): element:record_picker publishes every top-level key its spec props schema declares -> AssertionError: expected [ 'filter' ] to deeply equal [] the five A-class keys objectui#3808 / #3830 declared -> does not publish filter a JSX page writing `filter` -> `has no prop "filter"` (control: `searchFields` still reported, so the probe is not silently vacuous) 7 failed | 50 passed, restored to 57 passed. Verified: vitest packages/components/ + 4 console gates -> 116 files, 1111 tests passed vitest packages/sdui-parser/ + RefComponentWidget -> 5 files, 24 passed type-check @object-ui/components + @object-ui/console -> Done (after building the console dependency closure; the first run's TS2882s were stale artifacts) eslint on the three touched files -> 0 errors (12 pre-existing warnings in the untouched effect body) check-control-bytes / check-changeset-presence / -no-major / -fixed -> OK Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 #3830
filterappears in objectui#3808's raw key dump forelement:record_pickerand then in none of its A / B / C lists, so PR #3841 — the change that added the repo-wide parity gate — exempted it by name instead of declaring it. This declares it. It is the fourth gap of exactly the shape that PR fixed four times over: the spec declaresElementRecordPickerProps.filter, the renderer has read it all along, and the registryinputsnever mentioned it.Premise re-checked on current
origin/main(877385a76)All three legs still hold; two line numbers have drifted since the card was written, and one read expression has been rewritten:
record-picker.tsx:78,ds.filter ?? props.filter:105,composed?.filter ?? props.filteruseElementDataSourcerework (objectstack#6953) renamed the binding half; the precedence is unchangedquery.$filterat:103:129, plus thefilterKeymemo at:116inputsat:180-186omits it:224-230omits itWhat landed
1. The declaration (
packages/components/src/renderers/basic/record-picker.tsx). The description is derived from what the renderer does, per PR #3841's precedent, because the one thing an author cannot read off the spec is which of the two places they may write a filter wins:2.
type: 'object', not the sketch's'array'. Taken from the spec's actual shape on the resolved pin (@objectstack/spec@17.0.0-rc.5):filterisFilterConditionSchema, which isz.record(z.string(), z.unknown())intersected with the$and/$or/$notgroup — an object. Measured, not read:No
ComponentInputcompromise was needed, and that is itself the reportable data point for #3832.checkType's'object'arm insdui-parser/src/validate.tsaccepts a non-null non-array object and warnstype-mismatchon everything else — the same partitionsafeParsedraws above. So unlikeelement:text_input.defaultValue(specstring | number, published as'string', narrowing disclosed in prose), this key has no narrowing to disclose. #3832's union problem is real and untouched here; this key is simply the case where the coarse type costs nothing. The card's own warning aboutz.unknown()-style wide spec types did not materialise — worth knowing when #3832 is scoped, since it means the union limit is not uniform across the family.3. The exemption is deleted from
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, as that file's owncarries no stale unpublished-key exemptionassertion demands, and the key joins #3808's four in the by-name "declared, not merely not-failing" pin (now five).4. A per-block parity test,
packages/components/src/__tests__/record-picker-inputs-spec-parity.test.ts, followingtext-input-inputs-spec-parity.test.tsexactly — plus the one thing that precedent argued in prose but never executed: the JSX-page path, end to end.The JSX-page path, actually exercised
element:record_pickeris not inPUBLIC_BLOCKS("record picking is a field widget, not a page block"), so the gap was never insdui.manifest.json. It was in the JSX-page compiler's prop whitelist, whichrenderers/layout/page.tsxbuilds fromgetKnownTypes()plus these sameinputs. The new test assembles the manifest that way from the live registration and compiles a page that writesfilter.It carries its own non-vacuity control in the same
compile()call:searchFields— a spec key this block deliberately does not publish (an ADR-0087 tombstone upstream) — must still come back asunknown-prop. Without that control, "nounknown-propfor filter" is also what a broken manifest, an unregistered tag or a silent parse failure looks like.Reverse verification
Declaration reverted, exemption removal kept — the direction the card predicts:
The third line is the harm the card describes, reproduced verbatim: the compiler warning an author off
filterwhile the renderer filters the entire candidate set by it.Verification
type-checkneededpnpm --filter '@object-ui/console^...' buildfirst; the initial run'sTS2882 Cannot find module or type declarationserrors were stale artifacts, not a regression.Changeset:
@object-ui/componentspatch — the published authoring surface gains a declared input, the same argument class PR #3841 used.Out of scope, deliberately
The
#3832observation above is reported as a data point on the existing card, not acted on. No new issue filed: nothing new was found that is not already owned by #3832 (ComponentInputunion typing) or #3809 (tombstone recognition).Generated by Claude Code