Skip to content

refactor(ui-types): one source for the filter-builder field-type list, read by the schema, the interface and the renderer; close the three K4 review should-fixes #27369

Closed

Description

@objectstack-fleet

Filing gate ③ (maintainer-directed). This is the follow-up to K4 (#27145, PR #27329, merged 2026-10-29 03:51Z) of the objectui.org docs fold. In the "Restore objectui.org docs deploy" project thread on 2026-10-29, Tesla asked 「k4 从长远考虑应该怎么处理」. The dispatching seat answered: merge K4 as it is, then file one card that gives the filter-builder field-type list a single source and also takes the K4 review's three should-fixes. Tesla confirmed with 「K4 先合并,然后再单独派卡是吗」.

维护者速读

filter-builder 能接受的 14 种字段类型,现在由三处手写列表共同决定:校验 schema、TS 接口、K4 测试里冻结的那份列表。另外,渲染器里还有一份按行为划分的分组表。objectui#6939、#7562、#8774 修的都是这几份列表对不上的问题。本卡把渲染器的分组表搬到 @object-ui/types,作为唯一来源。schema、接口和渲染器都从这里引用,测试只校验两点:每个类型都有渲染分支,除 status(spec 里没有这个类型,单独列出豁免)外,每个类型都是 spec 的 FieldType。K4 合约评审的三条建议改项也一并处理。

Wanted

  1. One source. Move the renderer's behaviour buckets out of ui/packages/components/src/custom/filter-builder.tsx: numberLikeTypes (number, currency, percent, rating), dateLikeTypes (date, datetime, time), selectLikeTypes (select, status) and lookupLikeTypes (lookup, master_detail, user). Put them in a module of @object-ui/types, which @object-ui/components already depends on. Export from there the full accepted list, which is those buckets plus text and boolean, 14 members today.
    • FilterFieldSchema.type in ui/packages/types/src/zod/complex.zod.ts builds its z.enum from that list, and its .describe() stops citing "the published doc".
    • FilterField.type in ui/packages/types/src/complex.ts is typed from the same as const list, not restated as a union.
    • filter-builder.tsx imports the buckets and declares none of its own.
  2. The pin moves. ui/packages/types/src/__tests__/filter-builder-mirror-6939.test.ts drops the frozen LAST_PUBLISHED_TYPES list, which K4 added because its doc authority had gone. In its place it asserts that:
    • every member of the list has a branch in the renderer, using the existing per-member render measurement in examples/schema-catalog/test/filter-builder-mirror-6939.test.tsx;
    • every member is a member of FieldType in packages/spec/src/data/field.zod.ts, except an explicitly named exemption list. On main c4c515ad exactly one member needs an exemption: status is not a spec FieldType. Exempt it with a one-line reason, and do not drop it, because the accepted set must not narrow.
      Rewrite the header's objectstack#27145 section to say where the authority now lives. The accepted set must not change: still 14 members, type still optional, text still the default.
  3. K4 should-fix (1). The skill pointers in skills/objectui/guides/app-composition.md:62 and skills/objectui/rules/styling.md:318 are prose URLs, and no gate checks them. Either turn them into a form that check-skills-paths.mjs or check-doc-links.mjs already judges, or add skills to a gate's scan roots. State which in the PR.
  4. K4 should-fix (2). At .github/workflows/ci.yml:454 the comment says "four roots outside ui/", but the list under it has five globs. Correct the comment.
  5. K4 should-fix (3). ui/AGENTS.md:106 still tells contributors to update content/docs/guide/*.md, which no longer exists. Point it at content/docs/frontend/.

These should-fixes are recorded in triage's PASS records on #27329 (6485237613 on 6a7c7794, 6486708135 on df07a80e).

Who acts

A domain:devx card thread. The file surface is:

  • ui/packages/types/src/**, the new module plus the zod and interface lines;
  • ui/packages/components/src/custom/filter-builder.tsx;
  • the two filter-builder-mirror-6939 tests;
  • skills/objectui/{guides/app-composition.md,rules/styling.md};
  • ui/scripts/check-doc-links.mjs or ui/scripts/check-skills-paths.mjs and their tests, only if item 3 needs them;
  • .github/workflows/ci.yml, one comment line;
  • ui/AGENTS.md;
  • a changeset.

Item 4 makes the PR Tier H by path: it stays a draft until green, the triage seat writes the contract review, and the maintainer merges.

Business reason. A metadata author who puts a filter-builder in a page relies on two things agreeing: the types that validation accepts and the types the renderer draws. Today a third hand-kept list sits between them. Three past cards (objectui#6939, #7562, #8774) each fixed a case where these lists had drifted apart, and validation either refused a column the renderer could draw or accepted a spelling it drew as plain text. A single source removes that class of bug. The three should-fixes leave a stale pointer for contributors and two links that no gate checks.

Acceptance

  • git grep -n "LAST_PUBLISHED_TYPES\|published doc's fourteen" prints nothing.
  • Adding a fifteenth member to the shared list, without a renderer branch, makes the mirror test red. Removing one member from a bucket narrows the schema, the interface and the renderer together. Record both as one-time ablations in the PR.
  • pnpm --dir ui exec vitest run packages/types examples/schema-catalog is green, and the Lint UI steps are green.
  • The four components-complex-filter-builder/* catalog entries and the nested search-interface entry still validate.

Duplicate search. I ran a semantic issue search for "filter-builder FilterField type vocabulary single source list" on objectstack-ai/objectstack. Its one hit, #24640 (closed, about filterableFields), is a different surface. New.

Size: S–M. Clause-②: no. Metadata-protocol: none.

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-tesla · session_01L9qibyAYPFxpNP4BCr7Z82

    Claim: card thread "Fold objectui.org into objectstack docs", dispatch of #27369 (maintainer-directed: 「K4 先合并,然后再单独派卡是吗」, 2026-10-29 02:09Z, answering the seat's long-term proposal for the frozen filter-builder list)
    Session: session_01L9qibyAYPFxpNP4BCr7Z82 (dispatching thread) · dev: a new card thread the project coordinator opens for this card; it names its own session in its os-dev-report
    Account: os-tesla
    Branch: the dev card thread's platform-assigned claude/project-thread-* branch (mode:thread; the only branch it pushes)
    Worktree: the dev card thread's own checkout
    Domain: domain:devx
    Seat: domain:devx#1 (seat 1 by default; dispatched on the maintainer's instruction from a card thread, not from a lane seat)
    File surface: ui/packages/types/src/** (new shared module, zod/complex.zod.ts FilterFieldSchema.type, complex.ts FilterField.type, __tests__/filter-builder-mirror-6939.test.ts), ui/packages/components/src/custom/filter-builder.tsx (the four bucket declarations become imports), ui/examples/schema-catalog/test/filter-builder-mirror-6939.test.tsx, skills/objectui/guides/app-composition.md, skills/objectui/rules/styling.md, ui/scripts/{check-doc-links,check-skills-paths}.mjs and their tests (only if item 3 needs a scan-root row), .github/workflows/ci.yml (the one comment line at ~454), ui/AGENTS.md (line 106), one .changeset/*.md; ⛔ the accepted set does not change (14 members, type optional, text default; stop on breach)
    Container & model: M, mode:thread, model: opus, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: none
    Premise: holds (re-read on main c4c515ad: K4 #27329 merged as 7587fd4; LAST_PUBLISHED_TYPES is in ui/packages/types/src/__tests__/filter-builder-mirror-6939.test.ts; the four buckets are at filter-builder.tsx:1207–1223; FilterFieldSchema at zod/complex.zod.ts:582; status is the one member outside spec FieldType)
    Serial constraints cleared: none. Tier H by path (.github/workflows/ci.yml): draft until green, the triage seat renders the contract review, GOVERNED_APPROVERS review, the maintainer merges, and the seat never enqueues it.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-tesla · session_01L9qibxvBS38kVpxSqdV8T4

    os-dev-report

    {
     "issue": 27369,
     "status": "done",
     "branch": "claude/project-thread-jq1yxo",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/27400",
     "session": "session_01L9qibxvBS38kVpxSqdV8T4",
     "premise_still_valid": true,
     "summary": "FILTER_FIELD_TYPES and its four behaviour buckets now live in @object-ui/types (filter-field-types.ts); FilterFieldSchema.type, FilterField['type'] and filter-builder.tsx all read them. The mirror test drops LAST_PUBLISHED_TYPES and pins spec FieldType membership (status exempted by name) plus, in the render half, a branch per member. K4 should-fixes: check-doc-links scans skills/objectui (new per-row diskRoot; the two prose URLs became links; heading scan now reads blockquoted headings), ci.yml comment says five paths, ui/AGENTS.md #2 points at content/docs/frontend/. Accepted set unchanged.",
     "tests": "head 796bf3a3 (parent 7dc5d3f6 differs only in styling.md): pnpm --dir ui exec vitest run packages/types examples/schema-catalog -> Test Files 429/429, Tests 12850/12850; check-doc-links.test.ts 123/123; type-check exit 0 for @object-ui/types, @object-ui/components, @object-ui/example-schema-catalog. Ablations (src-aliased, restored from HEAD, status clean): +'email' without bucket -> render half 1 red; +'zz_not_spec' -> spec check 1 red; -'rating' from number bucket -> schema pin red, FilterField TS2322, render probe red.",
     "gates": "dispatch-gates --commands: 88 derived; 87 run exit 0 (token ratchet exit 1 on 7dc5d3f6 fixed to 0 on 796bf3a3; check:skill-examples exit 0 after client-react build); check:dual-build-cjs-loads exit 3 NOT MEASURED (needs full dist; CI runs it). --ran: 88 accounted, 87 run, 1 NOT-MEASURED. Lint UI lint:root + ui package lint: 0 errors. List: /mnt/project-files/d1-merge/out/27369-gates-ran-796bf3a3.list. CI: in_progress at report time.",
     "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "3 — issue_read x2, subscribe_pr_activity; no MCP write",
     "api_writes": "2 — relay pr_create (repository_dispatch, run 40821293906), this os-dev-report comment",
     "open_questions": [],
     "out_of_scope_findings": []
    }
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