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.

object-grid 的 inputs 声明 filters(复数),渲染器只读 filter(单数):按已发布词汇写筛选条件静默无效 #4041

Closed

Description

@os-zhuang

Migrated from objectstack-ai/objectstack#7119 under the file-at-destination ruling (objectstack-ai/objectstack#7167, maintainer 2026-08-10). Originally filed 2026-08-09T17:46:03Z. The full prior thread — including triage rulings and hold/restart conditions — remains on the source issue and MUST be read before acting on this card.


发现于 objectstack#6953 的实施过程(objectui 分支 claude/issue-6953-datasource-block-wiring),不在该单范围内,单独立单。

事实(objectui origin/main @ 65bb513 实测)

object-grid(以及同一渲染器的 view:grid 别名)的注册 inputs 声明的是复数 filters:

packages/plugin-grid/src/index.tsx
ComponentRegistry.register('object-grid', ObjectGridRenderer, {
  inputs: [
    { name: 'objectName', ... },
    { name: 'columns', ... },
    { name: 'filters', type: 'array', label: 'Filters' },   // ← 复数
  ]
});

而渲染器读的是单数 filter:

packages/plugin-grid/src/ObjectGrid.tsx:440  const schemaFilter = schema.filter;
packages/plugin-grid/src/ObjectGrid.tsx:615  params.$filter = schemaFilter;

schema.filters 在 ObjectGrid.tsx 里 grep 不到任何读点(唯一命中是文件头注释里的一句 "Search, filters, pagination")。同一仓的 list-view 声明的是单数 filter,与它自己的读点一致 —— 两个同族 block 对外发布了两种拼写,只有一个是真的。

症状

作者(或 AI)按 object-grid 已发布的 inputs/manifest 写 filters: [...],查询里没有 $filter,拿到全表 —— 不报错,SDUI 保存门也不会报 unknown-prop(filters 是已声明键)。反过来,写真正生效的 filter 时,filters 才是被 manifest 承认的那个名字,于是「发布的词汇」和「运行时读的键」指向相反。objectstack#4413 的形状,叠加 objectui#3407 那种「声明与读点拼写不一致」的变体。

为什么现有门禁看不见

  • check:react-declaration-parity 比的是两侧声明(spec zod props ↔ 本仓 inputs),不观察渲染器。
  • apps/console/src/__tests__/public-block-binding-reach.test.tsx 只问一个问题:声明了 objectName 的 block 有没有把对象名送到数据层。object-grid 送到了,所以它在那里是绿的 —— 该测试的文档也明确写了它不是「每个声明的 input 都被消费」的检查。

建议范围(需要判一次方向,别直接猜)

两条路,选哪条会落进公开契约,建议由维护者定:

  • A(推荐):把 inputs 改成单数 filter,与 list-view、与 spec 词汇、与渲染器读点三方对齐;filters 作为从未生效过的错误拼写直接去掉(它没有任何读点,不存在「已在野的可用写法」需要兼容)。
  • B:让渲染器额外读 filters。⛔ 这会把一个错误拼写固化成第二套 de-facto 契约(AGENTS.md #0.1),不建议。

无论哪条,需要一条钉子:按 inputs 声明的名字写筛选条件时,$filter 必须出现在查询里。

Activity

  1. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    Release-board grading (arrival pass): target:v17 added — class ②.

    The published inputs vocabulary declares filters (plural) while the renderer reads only filter (singular): filter conditions written per the published word are silently ineffective — declared ≠ enforced on a shipped surface, textbook class ②. The card is simultaneously in the decision inbox; board membership signals that this ruling should be prioritized because the release rides on it.

    Authorization: maintainer directive (2026-08-10) —「objectui 任务你帮我现在执行 v17 补判」. Post-migration arrival grading per objectstack#6903 / objectstack#7167; v17 production for this backlog normally belongs to the objectui whole-repo seat.

    Session: 01JaVVMrSxt7Tgi1uwEuDtH7


    Generated by Claude Code

  2. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    Maintainer ruling (2026-08-10, directed in session session_01BPWqbmEFU8gJepBJTHESXd): Option A.

    The inputs declaration becomes singular filter, aligned three ways — with the renderer's real read point, with list-view, and with spec vocabulary. filters is deleted outright: it has zero read points, so there is no in-the-wild working usage to keep compatible, and Option B would harden a misspelling into a second de-facto contract (AGENTS.md #0.1). Add the pin this card asks for: writing a filter under the declared name must produce $filter in the query.

    needs-user-decision → pm:queue; target:v17 stays.


    Generated by Claude Code

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

    @yinlianghui
    Contributor

    Claim: PM loop round 3 (objectui whole-repo seat, v17 board priority — final open dispatchable board item)
    Session: session_017Qqyix2QcnpUC9XeYVDzx3
    Branch: claude/issue-4041-grid-filter-input-spelling
    Worktree: objectui-issue-4041
    Domain: repo:objectui (whole-repo seat)
    File surface: packages/plugin-grid/src/index.tsx (registration inputs), packages/plugin-grid/src/ObjectGrid.tsx (read point unchanged unless the pin needs a hook) + tests; console parity/manifest gates only if mechanically forced by the rename (each move pinned, per the #4070 precedent). Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus
    Serial constraints cleared: no open claim or PR touches packages/plugin-grid; #3569's branch touches packages/fields/plugin-form (disjoint); all other board work MERGED this shift.

    Ruling in hand (maintainer, 2026-08-10, comment above): Option A — inputs becomes singular filter aligned three ways, filters deleted outright (zero read points, no in-the-wild working usage), plus the pin: a filter written under the declared name must produce $filter in the query.


    Generated by Claude Code

  5. yinlianghui commented on Aug 10, 2026

    @yinlianghui
    Contributor

    ACCEPT (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4081, implementing the maintainer's Option A ruling.

    What shipped: object-grid and its view:grid alias declare singular filter via one shared GRID_QUERY_INPUTS constant (the alias cannot drift); the never-read plural filters is deleted outright. Beyond the rename, the read point now lowers through toFilterNode — the source thread's binding 「本单实施时必须一并处理」 constraint, which my dispatch prompt under-scoped and the dev correctly honored (the prompt named the source thread authoritative): without the hop, an author writing spec ViewFilterRule[] under the newly-declared key would get a guaranteed 400 INVALID_FILTER instead of today's silent no-op — trading one failure for a worse one. The dev probed the pinned spec live to confirm rule objects already reach this read point via the spec bridge. Two narrow ride-along corrections toward the shared sink's documented contract (MongoDB-style object converted instead of dropped; empty filter: [] skips $filter), each independently reverse-verified. Changeset present; the pin reads the declared key name OUT of the registry so the test survives exactly the drift class this card is about.

    Review notes: premise anchors re-verified on current main plus a fourth (spec's own ListViewSchema.shape carries filter); downstream consumer sweep with the correct prefix filter direction (8 of 46 dependents, all clean, after building the closure — stale-artefact trap recognized, not misattributed). Both reverse verifications red in the predicted, independent directions. All 20 checks completed, 0 failures (Lint 06:09, Type Check 06:07, 4 shards 06:10-06:11 — per-job conclusions; the dev also documented a ~50-min stale check-runs listing and confirmed against the authoritative per-job records). Finding #4082 (defaultFilters leg bypassing the same hop) verified filed as observation-class with the honest "no live producer measured" caveat.

    Landing next: flipping ready and driving to MERGED — the last open dispatchable target:v17 item on this board.


    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

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions