Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

element:record_picker.filter 是渲染器实读、spec 已声明、inputs 不提的第 4 个 A 类缺口 —— #3808 的三类清单把它漏出了分类 #3830

Closed

Description

@yinlianghui

发现于 #3808 的实施过程(围栏外,本 PR 未夹带)。未认领,交 PM triage。

#3808 的分类漏了这一条

#3808 的实测清单里 element:record_picker 那一行是 5 个键:

element:record_picker  displayField, searchFields, filter, multiple, targetVariable

而下面的三类只交代了其中 4 个 —— C 类写了 displayField / searchFields / multiple(objectstack#5775 的 retiredKey() 墓碑)与 targetVariable(declarative hint),filter 没有出现在 A / B / C 任何一类里。它既不是墓碑,也不是 hint,而是标准的 A 类:渲染器实读 + spec 已声明 + inputs 不发布,和 #3808 修的那三条完全同形。

(#3808 正文自称「15 条」,按 block 逐行相加实为 13 条,C 类小计写 5 条实为 6 条 —— 分类过程中掉了一条,就是这个 filter。)

逐键证据(objectui origin/main @ c85268256,pin @objectstack/spec@17.0.0-rc.5)

  • spec 声明:ElementRecordPickerProps 的顶层键为 object, displayField, searchFields, filter, multiple, targetVariable, placeholder, aria(运行时 Object.keys(shape) 实测)。

  • 渲染器实读:packages/components/src/renderers/basic/record-picker.tsx:78

    const filter = ds.filter ?? props.filter;
    

    props 就是 readProps(schema),即节点顶层 props;filter 随后进 :103 的 query.$filter,并参与 :90 的 filterKey memo —— 是真正决定查什么记录的键,不是装饰。

  • inputs 不提:record-picker.tsx:180-186 只声明 object / labelField / valueField / placeholder / label。

有害在哪

element:record_picker 不在 PUBLIC_BLOCKS(packages/core/src/registry/public-blocks.ts:78 明确注释「record picking is a field widget, not a page block」),所以它不进 sdui.manifest.json。但它仍然发布一个运行时白名单:packages/components/src/renderers/layout/page.tsx:462 用 getKnownTypes() + 各自的 inputs 现搭一份 manifest 给 JSX 页面编译器。于是一个 JSX 页面写了 record picker 的 filter:

  1. sdui-parser/src/validate.ts:74 在 comp.inputs 里找不到它 → unknown-prop warning;
  2. 渲染器照样兑现它、照样按它过滤;
  3. 设计器面板里没有这个字段,作者也无从发现它存在。

三个层面三个答案,和 #3797 / #3808 要消掉的是同一件事。

为什么没在 #3808 里一起修

#3808 的判级评论把范围钉在「正文 A 类三条」+ record:related_list.add 的核对,并明确「C 类不动」。filter 落在分类之外,不在派发范围内 —— 按 Prime Directive #10 另开本单,而不是在那个 PR 里悄悄扩面。

落地

一行 inputs 声明,和 #3808 的四条同形:

{ name: 'filter', type: 'array', label: 'Filter', description: <从 :78/:103 的实际行为取材> }

注意 description 要交代 ds.filter ?? props.filter 的优先级(节点上的 dataSource.filter 压过顶层 filter),否则作者不知道两处都写时谁生效。type 取 'array' 还是 'object' 需按 spec 的实际 shape 定(filter 在 spec 里是 z.unknown() 一类的宽类型时,ComponentInput 的粗类型会产生误报 —— 见另一单)。

当前的兜底

#3808 落的反方向门把这一条列为带理由的显式豁免并引用本单;门里的 carries no stale exemption 断言会在有人声明它的那一刻要求删掉豁免条目。

参考位置

  • packages/components/src/renderers/basic/record-picker.tsx:78 / :90 / :103(读)、:180-186(声明)
  • packages/components/src/renderers/layout/page.tsx:462(运行时 JSX manifest)
  • packages/sdui-parser/src/validate.ts:74(unknown-prop)
  • apps/console/src/__tests__/registry-inputs-spec-parity.test.ts(两个方向的门 + 豁免名单)

关联:#3808、#3797 / PR #3806、#3407 / PR #3795、objectstack#5775

Activity

  1. claude commented on Aug 8, 2026

    @claude
    Contributor

    Triage: pm:queue.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 10, 2026
  3. yinlianghui commented on Aug 10, 2026

    @yinlianghui
    ContributorAuthor

    Claim: PM loop round 5 (rolling slot refill)
    Session: session_017Qqyix2QcnpUC9XeYVDzx3 · Branch: claude/issue-3830-record-picker-filter-input · Worktree: objectui-issue-3830
    File surface: packages/components/src/renderers/basic/record-picker.tsx (one inputs entry) + apps/console/src/__tests__/registry-inputs-spec-parity.test.ts (the explicit exemption this card is cited in must come OUT — the gate's own carries no stale exemption assertion demands it). Serial constraints: disjoint from the other four in flight.
    Container & model: S, mode:subagent, model: opus

    Direction is the card's own (#3808-shaped, 4th of the same class): declare filter in inputs with a description that documents the ds.filter ?? props.filter precedence; type chosen from the spec's actual shape on the resolved pin (the card warns ComponentInput's coarse typing can misreport wide spec types — if that bites, report it against the existing typing card rather than forcing a wrong arm).


    Generated by Claude Code

  4. yinlianghui commented on Aug 10, 2026

    @yinlianghui
    ContributorAuthor

    ACCEPT (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4112.

    The three premise legs re-verified with drift honestly recorded (the read moved to composed?.filter under the useElementDataSource rework; line shifts documented). Two card details corrected by measurement rather than inherited: type is 'object' — FilterConditionSchema on the resolved rc.5 rejects rule arrays, so the card's sketched 'array' would have published a wrong arm — and the description documents the ACTUAL precedence (a node-level dataSource filter DROPS the top-level key, not merges it), which is precisely the trap an author needed told about. The reverse verification's third red is the card's harm reproduced end to end with a built-in non-vacuity control (searchFields, deliberately unpublished, still reports unknown-prop in the same compile — so the healed case can't be faked by a broken manifest or silent parse). Exemption removed; the parity gate's stale-exemption assertion now enforces the declaration both ways. The #3832 data point (this key needed NO type compromise — the union limit is not uniform across the family) is exactly what that card's scoping will want.

    Flipping ready + auto-merge.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions